Aplikasi Tiga Tingkat

Arsitektur

Three Tier App adalah aplikasi daftar tugas sederhana yang dirancang sebagai aplikasi vanila 3 tingkat:

  • Backend
    • Database - MySQL - Cloud SQL
    • Menyimpan ke Cache - Redis - Cloud Memorystore
  • Middleware/API
    • API yang dihosting container - Golang - Cloud Run
  • Tampilan Depan/UI
    • UI yang dihosting container - Nginx + HTML/JS/CSS - Cloud Run
  • Deployment
    • Deployment Berkelanjutan - Cloud Build
    • Secret Management - Cloud Secret Manager

Mulai

Klik link berikut untuk mendapatkan salinan kode sumber di Cloud Shell. Setelah ada, satu perintah akan menjalankan salinan aplikasi yang berfungsi di project Anda..

Buka di Cloud Shell

Lihat kode sumber di GitHub


Komponen Aplikasi Tiga Tingkat

Arsitektur Aplikasi Tiga Tingkat menggunakan beberapa produk. Berikut ini daftar komponen, beserta informasi selengkapnya tentang komponen, termasuk link ke video terkait, dokumentasi produk, dan panduan interaktif.
Video Dokumen Panduan
Cloud SQL Cloud SQL adalah SQL terkelola yang menyediakan MySQL, SQL Server, atau Postgres untuk lapisan database aplikasi Anda.
Cloud Memorystore Cloud Memorystore, Redis terkelola, menyediakan lapisan cache untuk aplikasi Anda.
Cloud Run Cloud Run memungkinkan Anda untuk menjalankan aplikasi dalam container, tetapi dengan cara tanpa server, Anda tidak harus mengonfigurasi jumlah instance, prosesor, atau memori. Upload penampung, dapatkan URL.
Cloud Build Cloud Build adalah alat yang mengemas container dan men-deploy-nya agar tersedia sebagai layanan Cloud Run.
Secret Manager Cloud Secret Manager menyimpan informasi sensitif terkait aplikasi untuk proses build.

Skrip

Skrip penginstalan menggunakan file yang dapat dieksekusi yang ditulis di alat CLI Terraform dan go untuk mengambil project kosong dan menginstal aplikasi di dalamnya. Output harus berupa aplikasi yang berfungsi dan URL untuk alamat IP load balancing.

./main.tf

Mengaktifkan layanan

Layanan Google Cloud dinonaktifkan dalam project secara default. ToDo mengharuskan Anda mengaktifkan layanan berikut:

  • Jaringan Layanan & Akses VPC Serverless - memungkinkan Cloud Run untuk Berkomunikasi dengan SQL dan Redis di jaringan pribadi, sehingga server ini tidak dapat diakses dari panggilan luar yang berasal dari API.
  • Cloud Build - membuat image container dan men-deploy ke Cloud Run
  • Cloud Memorystore - menyediakan lapisan cache untuk aplikasi.
  • Cloud Run - alat serverless yang akan menghosting container, dan menyediakan URL tempat mengakses aplikasi.
  • Cloud SQL - penyimpanan database untuk aplikasi
  • Cloud Storage - digunakan oleh Cloud Build dan untuk memuat skema di database
  • Cloud Secret Manager - digunakan untuk memasukkan ip host untuk SQL dan Redis ke dalam Cloud Build for Cloud Run.
  • Artifact Registry - menyimpan image Docker untuk digunakan dengan Cloud Build.
variable "gcp_service_list" {
    description = "The list of apis necessary for the project"
    type        = list(string)
    default = [
        "compute.googleapis.com",
        "cloudapis.googleapis.com",
        "vpcaccess.googleapis.com",
        "servicenetworking.googleapis.com",
        "cloudbuild.googleapis.com",
        "sql-component.googleapis.com",
        "sqladmin.googleapis.com",
        "storage.googleapis.com",
        "secretmanager.googleapis.com",
        "run.googleapis.com",
        "artifactregistry.googleapis.com",
        "redis.googleapis.com"
    ]
}

resource "google_project_service" "all" {
    for_each                   = toset(var.gcp_service_list)
    project                    = var.project_number
    service                    = each.key
    disable_on_destroy = false
}

Tetapkan izin

Perintah berikut menetapkan Peran dan Izin IAM yang memungkinkan Cloud Build men-deploy layanan.

  • Mengaktifkan Akun Layanan Cloud Build untuk men-deploy ke Cloud Run
  • Aktifkan Akun Layanan Cloud Build untuk menetapkan Akses VPN untuk Cloud Run
  • Mengaktifkan Akun Layanan Cloud Build untuk menjalankan aktivitas Akun Layanan
  • Aktifkan Akun Layanan Cloud Build untuk bertindak atas nama Akun Layanan Compute
  • Aktifkan Akun Layanan Cloud Build untuk memublikasikan ke Cloud Run
  • Mengaktifkan Akun Layanan Cloud Build untuk menggunakan secret
  • Aktifkan Akun Layanan Cloud Build untuk menyimpan container di Artifact Registry
variable "build_roles_list" {
    description = "The list of roles that build needs for"
    type        = list(string)
    default = [
        "roles/run.developer",
        "roles/vpaccess.user",
        "roles/iam.serviceAccountUser",
        "roles/run.admin",
        "roles/secretmanager.secretAccessor",
        "roles/artifactregistry.admin",
    ]
}
resource "google_project_iam_member" "allbuild" {
    for_each   = toset(var.build_roles_list)
    project    = var.project_number
    role       = each.key
    member     = "serviceAccount:${local.sabuild}"
    depends_on = [google_project_service.all]
}

Membuat jaringan untuk instance SQL

Perintah berikut memungkinkan Cloud SQL dapat diakses dari Cloud Run:

resource "google_compute_global_address" "google_managed_services_vpn_connector" {
    name          = "google-managed-services-vpn-connector"
    purpose       = "VPC_PEERING"
    address_type  = "INTERNAL"
    prefix_length = 16
    network       = local.defaultnetwork
    project       = var.project_id
    depends_on    = [google_project_service.all]
}
resource "google_service_networking_connection" "vpcpeerings" {
    network                 = local.defaultnetwork
    service                 = "servicenetworking.googleapis.com"
    reserved_peering_ranges = [google_compute_global_address.google_managed_services_vpn_connector.name]
}

Buat konektor akses VPC

Menghubungkan Cloud Run ke Database dan Caching

resource "google_vpc_access_connector" "connector" {
    provider      = google-beta
    project       = var.project_id
    name          = "vpc-connector"
    ip_cidr_range = "10.8.0.0/28"
    network       = "default"
    region        = var.region
    depends_on    = [google_compute_global_address.google_managed_services_vpn_connector, google_project_service.all]
}

Membuat Server Redis

Mengonfigurasi dan melakukan inisialisasi instance server Redis.

resource "google_redis_instance" "todo_cache" {
    authorized_network      = local.defaultnetwork
    connect_mode            = "DIRECT_PEERING"
    location_id             = var.zone
    memory_size_gb          = 1
    name                    = "${var.basename}-cache"
    project                 = var.project_id
    redis_version           = "REDIS_6_X"
    region                  = var.region
    reserved_ip_range       = "10.137.125.88/29"
    tier                    = "BASIC"
    transit_encryption_mode = "DISABLED"
    depends_on              = [google_project_service.all]
}

Membuat server SQL

Perintah berikut mengonfigurasi dan menginisialisasi instance server SQL.

resource "google_sql_database_instance" "todo_database" {
    name="${var.basename}-db-${random_id.id.hex}"
    database_version = "MYSQL_5_7"
    region           = var.region
    project          = var.project_id
    settings {
        tier                  = "db-g1-small"
        disk_autoresize       = true
        disk_autoresize_limit = 0
        disk_size             = 10
        disk_type             = "PD_SSD"
        ip_configuration {
            ipv4_enabled    = false
            private_network = local.defaultnetwork
        }
        location_preference {
            zone = var.zone
        }
    }
    deletion_protection = false
    depends_on = [
        google_project_service.all,
        google_service_networking_connection.vpcpeerings
    ]
    # This handles loading the schema after the database installs.
    provisioner "local-exec" {
        working_dir = "${path.module}/code/database"
        command     = "./load_schema.sh ${var.project_id} ${google_sql_database_instance.todo_database.name}"
    }
}

Membuat repositori Artifact Registry

Perintah berikut menyimpan Image Docker untuk digunakan dengan Cloud Run.

resource "google_artifact_registry_repository" "todo_app" {
    provider      = google-beta
    format        = "DOCKER"
    location      = var.region
    project       = var.project_id
    repository_id = "${var.basename}-app"
    depends_on    = [google_project_service.all]
}

Membuat secret

Perintah berikut menyimpan data host Redis dan SQL di Cloud Secrets.

resource "google_secret_manager_secret" "redishost" {
    project = var.project_number
    replication {
        automatic = true
    }
    secret_id  = "redishost"
    depends_on = [google_project_service.all]
}
resource "google_secret_manager_secret_version" "redishost" {
    enabled     = true
    secret      = "projects/${var.project_number}/secrets/redishost"
    secret_data = google_redis_instance.todo_cache.host
    depends_on  = [google_project_service.all, google_redis_instance.todo_cache, google_secret_manager_secret.redishost]
}
resource "google_secret_manager_secret" "sqlhost" {
    project = var.project_number
    replication {
        automatic = true
    }
    secret_id  = "sqlhost"
    depends_on = [google_project_service.all]
}
resource "google_secret_manager_secret_version" "sqlhost" {
    enabled     = true
    secret      = "projects/${var.project_number}/secrets/sqlhost"
    secret_data = google_sql_database_instance.todo_database.private_ip_address
    depends_on  = [google_project_service.all, google_sql_database_instance.todo_database, google_secret_manager_secret.sqlhost]
}

Membuat artefak untuk middleware

Perintah berikut membuat image Docker dan menghostingnya di Artifact Registry: ./code/frontend/clouldbuild.yaml

resource "null_resource" "cloudbuild_api" {
  provisioner "local-exec" {
    working_dir = "${path.module}/code/middleware"
    command     = "gcloud builds submit . --substitutions=_REGION=${var.region},_BASENAME=${var.basename}"
  }
  depends_on = [
    google_artifact_registry_repository.todo_app,
    google_secret_manager_secret_version.redishost,
    google_secret_manager_secret_version.sqlhost,
    google_project_service.all
  ]
}

Men-deploy container API ke Cloud Run

Perintah berikut menggunakan Cloud Build untuk menjalankan layanan di Cloud Run menggunakan container yang baru saja Anda bangun.

resource "google_cloud_run_service" "api" {
    name     = "${var.basename}-api"
    location = var.region
    project  = var.project_id

    template {
        spec {
            containers {
                image = "${var.region}-docker.pkg.dev/${var.project_id}/${var.basename}-app/api"
                env {
                    name = "REDISHOST"
                    value_from {
                        secret_key_ref {
                            name = google_secret_manager_secret.redishost.secret_id
                            key  = "latest"
                        }
                    }
                }
                env {
                    name = "todo_host"
                    value_from {
                        secret_key_ref {
                        name = google_secret_manager_secret.sqlhost.secret_id
                        key  = "latest"
                        }
                    }
                }
                env {
                    name  = "todo_user"
                    value = "todo_user"
                }
                env {
                    name  = "todo_pass"
                    value = "todo_pass"
                }
                env {
                    name  = "todo_name"
                    value = "todo"
                }
                env {
                    name  = "REDISPORT"
                    value = "6379"
                }
            }
        }
        metadata {
            annotations = {
                "autoscaling.knative.dev/maxScale"        = "1000"
                "run.googleapis.com/cloudsql-instances"   = google_sql_database_instance.todo_database.connection_name
                "run.googleapis.com/client-name"          = "terraform"
                "run.googleapis.com/vpc-access-egress"    = "all"
                "run.googleapis.com/vpc-access-connector" = google_vpc_access_connector.connector.id
            }
        }
    }
    autogenerate_revision_name = true
    depends_on = [
        null_resource.cloudbuild_api,
        google_project_iam_member.secretmanager_secretAccessor
    ]
}

Membuka Layanan Cloud Run API agar dapat dibaca oleh semua orang.

Lapisan API aplikasi ini akan dipanggil oleh browser pengguna, tetapi secara default layanan Cloud Run tidak bersifat publik. Agar pengguna dapat menggunakan layanan ini, kita harus membuka izin pada layanan ini agar dapat diakses oleh dunia.

resource "google_cloud_run_service_iam_policy" "noauth_api" {
    location    = google_cloud_run_service.api.location
    project     = google_cloud_run_service.api.project
    service     = google_cloud_run_service.api.name
    policy_data = data.google_iam_policy.noauth.policy_data
}

Membuat artefak untuk front end

Perintah berikut membuat image Docker dan menghostingnya di Artifact Registry: ./code/frontend/clouldbuild.yaml

resource "null_resource" "cloudbuild_fe" {
    provisioner "local-exec" {
        working_dir = "${path.module}/code/frontend"
        command     = "gcloud builds submit . --substitutions=_REGION=${var.region},_BASENAME=${var.basename}"
    }
    depends_on = [
        google_artifact_registry_repository.todo_app,
        google_cloud_run_service.api
    ]
}

Men-deploy container front end ke Cloud Run

Perintah berikutnya menggunakan Cloud Build untuk menjalankan layanan di Cloud Run menggunakan container yang baru saja kita bangun

resource "google_cloud_run_service" "fe" {
    name     = "${var.basename}-fe"
    location = var.region
    project  = var.project_id
    template {
        spec {
            containers {
                image = "${var.region}-docker.pkg.dev/${var.project_id}/${var.basename}-app/fe"
                ports {
                    container_port = 80
                }
            }
        }
    }
    depends_on = [null_resource.cloudbuild_fe]
}

Membuka layanan frontend Cloud Run agar dapat dibaca di seluruh dunia

Ini adalah frontend aplikasi, yang akan merender HTML/JS/CSS yang digunakan pengguna untuk berinteraksi dengan aplikasi - secara default layanan Cloud Run tidak bersifat publik. Agar aplikasi ini dapat berfungsi, kami harus membuka izin pada layanan ini agar dapat diakses oleh dunia.

resource "google_cloud_run_service_iam_policy" "noauth_fe" {
    location    = google_cloud_run_service.fe.location
    project     = google_cloud_run_service.fe.project
    service     = google_cloud_run_service.fe.name
    policy_data = data.google_iam_policy.noauth.policy_data
}

./code/database/load_schema.sh

Menginisialisasi skema database

Perintah ini membuat bucket Cloud Storage sementara untuk mengupload skema ke Cloud SQL.

PROJECT=$1
SQLNAME=$2

SQLSERVICEACCOUNT=$(gcloud sql instances describe $SQLNAME --format="value(serviceAccountEmailAddress)" | xargs)
gsutil mb gs://$PROJECT-temp
gsutil cp schema.sql gs://$PROJECT-temp/schema.sql
gsutil iam ch serviceAccount:$SQLSERVICEACCOUNT:objectViewer gs://$PROJECT-temp/
gcloud sql import sql $SQLNAME gs://$PROJECT-temp/schema.sql -q
gsutil rm gs://$PROJECT-temp/schema.sql
gsutil rb gs://$PROJECT-temp

./code/middleware/clouldbuild.yaml

Membangun penampung API

Kode ini membuat image Docker untuk lapisan middleware.

name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', '$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/api', '.' ]
  ```
#### Push API container to Artifact Registry
Pushing the container to Artifact Registry makes it possible for Cloud Run to
get the image and serve it.

``` yaml
name: 'gcr.io/cloud-builders/docker'
args: ['push', '$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/api']

Substitusi

Kode berikut membuat variabel dengan nilai default sehingga nilai tersebut dapat diubah pada waktu deployment.

substitutions:
  _REGION: us-central1
  _BASENAME: todo

./code/frontend/clouldbuild.yaml

Konten kode pijat

Tampilan depan benar-benar statis/JS/CSS. Aplikasi harus mengarah ke URL untuk layanan API yang baru saja kita buat, tetapi layanan Cloud Run diberi URL dengan string acak. 'Skrip pijat' ini menangkap URL acak dan memasukkannya ke dalam kode JS statis dalam container ini.

./code/frontend/massage.sh

name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: bash
args: [ './massage.sh', '$_REGION' ]

Membangun penampung API

Kode berikut membuat image Docker untuk lapisan middleware:

name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', '$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/fe', '.' ]

Mengirim container API ke Artifact Registry

Mengirim container ke Artifact Registry memungkinkan Cloud Run mendapatkan image dan menayangkannya.

name: 'gcr.io/cloud-builders/docker'
args: ['push', '$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/fe']

Substitusi

Buat variabel dengan default agar nilai tersebut dapat diubah pada waktu deployment.

substitutions:
  _REGION: us-central1
  _BASENAME: todo

./code/frontend/massage.sh

Edit JavaScript

Perintah ini memasukkan endpoint untuk Middleware ke JavaScript front end.

API=$(gcloud run services describe todo-api --region=$1 --format="value(status.url)")
stripped=$(echo ${API/https:\/\//})
sed -i"" -e "s/127.0.0.1:9000/$stripped/" www/js/main.js

Kesimpulan

Anda kini memiliki aplikasi daftar tugas 3 tingkat sederhana yang berjalan di Cloud Run di project Anda. Anda juga memiliki semua kode untuk dimodifikasi atau memperluas solusi ini agar sesuai dengan lingkungan Anda.