Three Tier App è una semplice applicazione per la gestione delle attività progettata come applicazione a tre livelli standard:
- Backend
- Database - MySQL - Cloud SQL
- Memorizzazione nella cache - Redis - Cloud Memorystore
- Middleware/API
- API ospitata in un container - Golang - Cloud Run
- Front-end/UI
- Interfaccia utente ospitata in un contenitore - Nginx + HTML/JS/CSS - Cloud Run
- Deployment
- Deployment continuo - Cloud Build
- Gestione dei secret - Cloud Secret Manager
Inizia
Fai clic sul seguente link per una copia del codice sorgente in Cloud Shell. Una volta un singolo comando avvierà una copia funzionante dell'applicazione progetto...
Visualizza il codice sorgente su GitHub
Componenti dell'app a tre livelli
L'architettura delle app a tre livelli utilizza diversi prodotti. Di seguito sono elencati i componenti, insieme a ulteriori informazioni su di essi, inclusi link a video correlati, documentazione del prodotto e walkthrough interattivi.Script
Lo script di installazione usa un eseguibile scritto negli strumenti dell'interfaccia a riga di comando go
e Terraform per
installare l'applicazione al suo interno
in un progetto vuoto. L'output dovrebbe essere un
e un URL per l'indirizzo IP del bilanciamento del carico.
./main.tf
Attiva i servizi
I servizi Google Cloud sono disabilitati in un progetto per impostazione predefinita. Per utilizzare ToDo, devi attivare i seguenti servizi:
- Networking di servizi e Accesso VPC serverless: consente a Cloud Run di Comunica con SQL e Redis su una rete privata mantenendo questi server inaccessibili da chiamate esterne provenienti dall'API.
- Cloud Build: crea immagini container ed esegue il deployment in Cloud Run
- Cloud Memorystore: fornisce un livello di memorizzazione nella cache per l'applicazione.
- Cloud Run: lo strumento serverless che ospiterà i container. fornire URL da cui accedere all'applicazione.
- Cloud SQL: spazio di archiviazione del database per l'applicazione
- Cloud Storage: utilizzato da Cloud Build e per caricare lo schema nel database
- Cloud Secret Manager: utilizzato per iniettare gli IP host per SQL e Redis in Cloud Build per Cloud Run.
- Artifact Registry: memorizza le immagini Docker da utilizzare con 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
}
Imposta autorizzazioni
Il seguente comando imposta i ruoli e le autorizzazioni IAM che consentono a Cloud Build di eseguire il deployment dei servizi.
- Abilita l'account di servizio Cloud Build per eseguire il deployment in Cloud Run
- Abilita l'account di servizio Cloud Build per impostare l'accesso VPN per Cloud Run
- Consenti all'account di servizio Cloud Build di eseguire attività dell'account di servizio
- Abilitare l'account di servizio Cloud Build per agire per conto dell'account di servizio Compute
- Abilita l'account di servizio Cloud Build per pubblicare in Cloud Run
- Abilita l'account di servizio Cloud Build per utilizzare i secret
- Abilita l'account di servizio Cloud Build per archiviare container in 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]
}
Crea la rete per l'istanza SQL
Il seguente comando consente di accedere a Cloud SQL da 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]
}
Crea un connettore di accesso VPC
Collega Cloud Run al database e alla memorizzazione nella 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]
}
Crea il server Redis
Configura e inizializza un'istanza del 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]
}
Crea SQL Server
Il seguente comando configura e inizializza un'istanza SQL Server.
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}"
}
}
Crea un repository Artifact Registry
Il seguente comando memorizza le immagini Docker per l'utilizzo con 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]
}
Creare secret
Il seguente comando memorizza i dati degli host Redis e SQL in 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]
}
Creazione artefatto per middleware
Il comando seguente crea l'immagine Docker e la ospita su 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
]
}
Esegui il deployment del container API in Cloud Run
Il seguente comando utilizza Cloud Build per avviare un servizio su Cloud Run utilizzando il contenitore appena creato.
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
]
}
Apri il servizio API Cloud Run in modo che sia leggibile da tutti.
Questo livello API dell'applicazione verrà chiamato dal browser dell'utente, ma per impostazione predefinita i servizi Cloud Run non sono pubblici. Affinché gli utenti possano usufruire di questo servizio, dobbiamo aprire le autorizzazioni su questi servizi in modo che siano accessibili a tutti.
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
}
Crea artefatto per front-end
Il seguente comando crea l'immagine Docker e la ospita su 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
]
}
Esegui il deployment del container frontend in Cloud Run
Il comando successivo utilizza Cloud Build per avviare un servizio su Cloud Run utilizzando il container che abbiamo appena creato
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]
}
Apri il servizio frontend Cloud Run per essere leggibile da tutto il mondo
Questo è il front-end dell'applicazione, che eseguirà il rendering dei file HTML/JS/CSS. tramite il quale l'utente interagisce con l'applicazione: per impostazione predefinita, i servizi Cloud Run non sono pubblici. Per far funzionare questa applicazione dobbiamo aprire affinché tutti possano accedere a questi servizi.
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
Inizializza schema del database
Questo comando crea un bucket Cloud Storage temporaneo per caricare lo schema in 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
Container API Build
Questo codice crea un'immagine Docker per il livello 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']
Sostituzioni
Il codice seguente crea variabili con valori predefiniti in modo che questi valori possano essere modificati al momento del deployment.
substitutions:
_REGION: us-central1
_BASENAME: todo
./code/frontend/clouldbuild.yaml
Massaggiare i contenuti del codice
Il front-end è completamente statico HTML/JS/CSS. L'app deve puntare all'URL del servizio API che abbiamo appena creato, ma ai servizi Cloud Run viene assegnato un URL con una stringa randomizzata. "Testo per il massaggio" acquisisce l'URL casuale e lo inserisce nel codice del codice JS statico in questo container.
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: bash
args: [ './massage.sh', '$_REGION' ]
Crea un contenitore API
Il seguente codice crea un'immagine Docker per il livello middleware:
name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', '$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/fe', '.' ]
Esegui il push del container API in Artifact Registry
Il push del container in Artifact Registry consente a Cloud Run di ottenere l'immagine e pubblicarla.
name: 'gcr.io/cloud-builders/docker'
args: ['push', '$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/fe']
Sostituzioni
Crea una variabile con un valore predefinito in modo che questi valori possano essere modificati al momento del deployment.
substitutions:
_REGION: us-central1
_BASENAME: todo
./code/frontend/massage.sh
Modifica JavaScript
Questo comando inserisce l'endpoint per il middleware nel codice JavaScript del 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
Conclusione
Ora hai una semplice applicazione di promemoria a 3 livelli in esecuzione su Cloud Esegui nel progetto. Hai anche tutto il codice per modificare o estendere questa soluzione in base al tuo ambiente.