Aplikasi Tiga Tingkat adalah aplikasi daftar tugas sederhana yang dirancang sebagai aplikasi 3 tingkat vanilla:
- Backend
- Database - MySQL - Cloud SQL
- Penyimpanan dalam Cache - Redis - Cloud Memorystore
- Middleware/API
- API yang dihosting container - Golang - Cloud Run
- Front End/UI
- UI yang dihosting container - Nginx + HTML/JS/CSS - Cloud Run
- Deployment
- Deployment Berkelanjutan - Cloud Build
- Pengelolaan Secret - Cloud Secret Manager
Mulai
Klik link berikut untuk melihat salinan kode sumber di Cloud Shell. Setelah di sana, satu perintah akan membuat salinan aplikasi yang berfungsi di project Anda.
Komponen Aplikasi Tiga Tingkat
Arsitektur Aplikasi Tiga Tingkat menggunakan beberapa produk. Berikut adalah daftar komponen, beserta informasi selengkapnya tentang komponen tersebut, termasuk link ke video terkait, dokumentasi produk, dan panduan interaktif.Skrip
Skrip penginstalan menggunakan file yang dapat dieksekusi yang ditulis di go
dan alat Terraform CLI untuk mengambil project kosong dan menginstal aplikasi di dalamnya. Output-nya harus berupa aplikasi yang berfungsi dan URL untuk alamat IP load balancing.
./main.tf
Mengaktifkan layanan
Layanan Google Cloud dinonaktifkan di project secara default. ToDo mengharuskan Anda mengaktifkan layanan berikut:
- Service Networking & Serverless VPC Access - 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 penyimpanan cache untuk aplikasi.
- Cloud Run - alat serverless yang akan menghosting container, dan menyediakan URL untuk 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 Cloud Build untuk 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
}
Menetapkan 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
- Mengaktifkan Akun Layanan Cloud Build untuk menetapkan Akses VPN untuk Cloud Run
- Mengaktifkan Akun Layanan Cloud Build untuk melakukan aktivitas Akun Layanan
- Mengaktifkan Akun Layanan Cloud Build untuk bertindak atas nama Akun Layanan Compute
- Mengaktifkan Akun Layanan Cloud Build untuk memublikasikan ke Cloud Run
- Mengaktifkan Akun Layanan Cloud Build untuk menggunakan secret
- Mengaktifkan Akun Layanan Cloud Build untuk menyimpan penampung 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 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]
}
Membuat konektor akses VPC
Menghubungkan Cloud Run ke Database dan Cache
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 menginisialisasi 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 meluncurkan layanan di Cloud Run menggunakan container yang baru saja Anda build.
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
]
}
Buka 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, kami harus membuka izin pada layanan ini agar dapat diakses oleh semua orang.
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 frontend
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 frontend ke Cloud Run
Perintah berikutnya menggunakan Cloud Build untuk meluncurkan layanan di Cloud Run menggunakan container yang baru saja kita build
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 oleh semua orang
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 berfungsi, kita harus membuka izin pada layanan ini agar dapat diakses oleh semua orang.
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
Melakukan inisialisasi 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)
gcloud storage buckets create gs://$PROJECT-temp
gcloud storage cp schema.sql gs://$PROJECT-temp/schema.sql
gcloud storage buckets add-iam-policy-binding gs://$PROJECT-temp/ --member=serviceAccount:$SQLSERVICEACCOUNT --role=roles/storage.objectViewer
gcloud sql import sql $SQLNAME gs://$PROJECT-temp/schema.sql -q
gcloud storage rm gs://$PROJECT-temp --recursive
./code/middleware/clouldbuild.yaml
Membuat 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 ini dapat diubah pada waktu deployment.
substitutions:
_REGION: us-central1
_BASENAME: todo
./code/frontend/clouldbuild.yaml
Konten kode pijat
Front end sepenuhnya berupa HTML/JS/CSS statis. Aplikasi harus mengarah ke URL untuk layanan API yang baru saja kita buat, tetapi layanan Cloud Run diberi URL dengan string acak. 'Skrip massage' ini mengambil URL acak tersebut dan memasukkannya ke dalam kode JS statis di penampung ini.
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: bash
args: [ './massage.sh', '$_REGION' ]
Membuat 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 sehingga nilai ini dapat diubah pada waktu deployment.
substitutions:
_REGION: us-central1
_BASENAME: todo
./code/frontend/massage.sh
Mengedit JavaScript
Perintah ini memasukkan endpoint untuk Middleware ke dalam JavaScript frontend.
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
Sekarang Anda memiliki aplikasi daftar tugas 3 tingkat sederhana yang berjalan di Cloud Run dalam project Anda. Anda juga memiliki semua kode untuk mengubah atau memperluas solusi ini agar sesuai dengan lingkungan Anda.