Conecta Cloud Spanner con GKE Autopilot

1. Introducción

Cloud Spanner es un servicio de base de datos relacional completamente administrado, escalable horizontalmente y distribuido a nivel global que proporciona transacciones ACID y semántica de SQL sin renunciar al rendimiento ni a la alta disponibilidad.

GKE Autopilot es un modo de operación en GKE en el que Google administra la configuración de tu clúster, incluidos los nodos, el escalamiento, la seguridad y otros parámetros de configuración preestablecidos para seguir las prácticas recomendadas. Por ejemplo, GKE Autopilot permite que Workload Identity administre los permisos de servicio.

El objetivo de este lab es guiarte a través del proceso de conectar varios servicios de backend que se ejecutan en GKE Autopilot a una base de datos de Cloud Spanner.

3d810aa9ec80a271.png

En este lab, primero configurarás un proyecto y, luego, iniciarás Cloud Shell. Luego, implementarás la infraestructura con Terraform.

Cuando finalice, interactuarás con Cloud Build y Cloud Deploy para realizar una migración inicial del esquema de la base de datos de Juegos, implementar los servicios de backend y, luego, implementar las cargas de trabajo.

Los servicios de este codelab son los mismos del codelab Cómo comenzar a usar el desarrollo de juegos en Cloud Spanner. Completar ese codelab no es un requisito para que los servicios se ejecuten en GKE y se conecten a Spanner. Pero si quieres obtener más detalles sobre los detalles de los servicios que funcionan en Spanner, consúltalos.

Con las cargas de trabajo y los servicios de backend en ejecución, puedes comenzar a generar carga y observar cómo funcionan los servicios en conjunto.

Por último, limpiarás los recursos que se crearon en este lab.

Qué compilarás

Como parte de este lab, aprenderás a hacer lo siguiente:

  • Aprovisionar la infraestructura con Terraform
  • Crea el esquema de la base de datos mediante un proceso de migración de esquemas en Cloud Build
  • Implementa los cuatro servicios de backend de Golang que aprovechan Workload Identity para conectarse a Cloud Spanner
  • Implementar los cuatro servicios de carga de trabajo que se usan para simular la carga para los servicios de backend

Qué aprenderás

  • Cómo aprovisionar canalizaciones de GKE Autopilot, Cloud Spanner y Cloud Deploy con Terraform
  • Cómo Workload Identity permite que los servicios en GKE actúen en nombre de las cuentas de servicio para acceder a los permisos de IAM y trabajar con Cloud Spanner.
  • Cómo generar una carga similar a la de producción en GKE y Cloud Spanner con Locust.io

Requisitos

  • Un proyecto de Google Cloud que esté conectado a una cuenta de facturación
  • Un navegador, como Chrome o Firefox.

2. Configuración y requisitos

Crea un proyecto

Si aún no tienes una Cuenta de Google (Gmail o Google Apps), debes crear una. Accede a la consola de Google Cloud Platform ( console.cloud.google.com) y crea un proyecto nuevo.

Si ya tienes un proyecto, haz clic en el menú desplegable de selección de proyectos en la parte superior izquierda de la Console:

6c9406d9b014760.png

y haz clic en “NUEVO PROYECTO”. del diálogo resultante para crear un proyecto nuevo:

949d83c8a4ee17d9.png

Si aún no tienes un proyecto, deberías ver un cuadro de diálogo como este para crear el primero:

870a3cbd6541ee86.png

El cuadro de diálogo de creación posterior del proyecto te permite ingresar los detalles de tu proyecto nuevo:

6a92c57d3250a4b3.png

Recuerda el ID del proyecto, que es un nombre único en todos los proyectos de Google Cloud (el nombre anterior ya se encuentra en uso y no lo podrá usar). Se mencionará más adelante en este codelab como PROJECT_ID.

A continuación, si aún no lo has hecho, deberás habilitar la facturación en Developers Console para usar los recursos de Google Cloud y habilitar la API de Cloud Spanner.

15d0ef27a8fbab27.png

Ejecutar este codelab debería costar solo unos pocos dólares, pero su costo podría aumentar si decides usar más recursos o si los dejas en ejecución (consulta la sección “Limpiar” al final de este documento). Los precios de Google Cloud Spanner se documentan aquí, y GKE Autopilot se documenta aquí.

Los usuarios nuevos de Google Cloud Platform están aptas para obtener una prueba gratuita de $300, por lo que este codelab es completamente gratuito.

Configuración de Cloud Shell

Si bien Google Cloud y Spanner se pueden operar de manera remota desde tu laptop, en este codelab usaremos Google Cloud Shell, un entorno de línea de comandos que se ejecuta en la nube.

Esta máquina virtual basada en Debian está cargada con todas las herramientas de desarrollo que necesitarás. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Esto significa que todo lo que necesitarás para este Codelab es un navegador (sí, funciona en una Chromebook).

  1. Para activar Cloud Shell desde la consola de Cloud, simplemente haz clic en Activar Cloud Shell gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A (el aprovisionamiento y la conexión al entorno debería tardar solo unos momentos).

JjEuRXGg0AYYIY6QZ8d-66gx_Mtc-_jDE9ijmbXLJSAXFvJt-qUpNtsBsYjNpv2W6BQSrDc1D-ARINNQ-1EkwUhz-iUK-FUCZhJ-NtjvIEx9pIkE-246DomWuCfiGHK78DgoeWkHRw

Captura de pantalla del 14 de junio de 2017 a las 10.13.43 p.m. .png

Una vez conectado a Cloud Shell, debería ver que ya se autenticó y que el proyecto ya se configuró con tu PROJECT_ID:

gcloud auth list

Resultado del comando

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

Si, por algún motivo, el proyecto no está configurado, solo emite el siguiente comando:

gcloud config set project <PROJECT_ID>

Si no conoce su PROJECT_ID, Observa el ID que usaste en los pasos de configuración o búscalo en el panel de la consola de Cloud:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

Cloud Shell también configura algunas variables de entorno de forma predeterminada, lo que puede resultar útil cuando ejecutas comandos futuros.

echo $GOOGLE_CLOUD_PROJECT

Resultado del comando

<PROJECT_ID>

Descarga el código

En Cloud Shell, puedes descargar el código de este lab:

git clone https://github.com/cloudspannerecosystem/spanner-gaming-sample.git

Resultado del comando

Cloning into 'spanner-gaming-sample'...
*snip*

Este codelab se basa en la versión v0.1.3, así que verifica esa etiqueta:

cd spanner-gaming-sample
git fetch --all --tags

# Check out v0.1.3 release
git checkout tags/v0.1.3 -b v0.1.3-branch

Resultado del comando

Switched to a new branch 'v0.1.3-branch'

Ahora, configura el directorio de trabajo actual como la variable de entorno DEMO_HOME. Esto te facilitará la navegación a medida que trabajes en las diferentes partes del codelab.

export DEMO_HOME=$(pwd)

Resumen

En este paso, configuraste un proyecto nuevo, activaste Cloud Shell y descargaste el código del lab.

Cuál es el próximo paso

A continuación, aprovisionarás la infraestructura con Terraform.

3. Aprovisiona la infraestructura

Descripción general

Con el proyecto listo, es hora de poner en marcha la infraestructura. Esto incluye las herramientas de redes de VPC, Cloud Spanner, GKE Autopilot, Artifact Registry para almacenar las imágenes que se ejecutarán en GKE, las canalizaciones de Cloud Deploy para los servicios de backend y las cargas de trabajo y, por último, las cuentas de servicio y los privilegios de IAM para poder usar esos servicios.

Es mucha información. Por suerte, Terraform puede simplificarte la configuración. Terraform es una solución de “infraestructura como código” que nos permite especificar lo que necesitamos para este proyecto en una serie de archivos archivos. Esto simplifica el aprovisionamiento de la infraestructura.

Familiarizarte con Terraform no es obligatorio para completar este codelab. Sin embargo, si quieres saber cuáles son los próximos pasos, puedes ver qué se crea en estos archivos ubicados en el directorio infrastructure:

  • vpc.tf
  • backend_gke.tf
  • spanner.tf
  • artifact_registry.tf
  • pipelines.tf
  • iam.tf

Configura Terraform

En Cloud Shell, cambiarás al directorio infrastructure y, luego, inicializarás Terraform:

cd $DEMO_HOME/infrastructure
terraform init

Resultado del comando

Initializing the backend...

Initializing provider plugins...
*snip*
Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

A continuación, configura Terraform copiando terraform.tfvars.sample y modificando el valor del proyecto. Las otras variables también se pueden cambiar, pero el proyecto es el único que debe modificarse para que funcione con tu entorno.

cp  terraform.tfvars.sample terraform.tfvars
# edit gcp_project using the project environment variable
sed -i "s/PROJECT/$GOOGLE_CLOUD_PROJECT/" terraform.tfvars

Aprovisiona la infraestructura

Ahora es el momento de aprovisionar la infraestructura.

terraform apply
# review the list of things to be created
# type 'yes' when asked

Resultado del comando

Plan: 46 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

google_project_service.project["container.googleapis.com"]: Creating...
*snip*
Apply complete! Resources: 46 added, 0 changed, 0 destroyed.

Revisa lo que se creó

Para verificar lo que se creó, revisa los productos en la consola de Cloud.

Cloud Spanner

Primero, navega hasta el menú de opciones y haz clic en Spanner para verificar Cloud Spanner. Es posible que debas hacer clic en “Ver más productos” para encontrarla en la lista.

Esta acción te llevará a la lista de instancias de Spanner. Haz clic en la instancia para ver las bases de datos. Debería verse algo similar a esto:

10b7fc0c4a86c59.png

GKE Autopilot

A continuación, navega hasta el menú de opciones y haz clic en Kubernetes Engine => Clusters para verificar GKE. Aquí verás el clúster sample-games-gke ejecutándose en modo Autopilot.

9cecb1a702e6b7ff.png

Artifact Registry

Ahora, quieres ver dónde se almacenarán las imágenes. Para ello, haz clic en el menú de hamburguesa y busca Artifact Registry=>Repositories. Artifact Registry se encuentra en la sección CI/CD del menú.

Aquí, verás un registro de Docker llamado spanner-game-images. Por ahora, este campo estará vacío.

3f805eee312841b.png

Cloud Deploy

Cloud Deploy es donde se crearon las canalizaciones para que Cloud Build pudiera proporcionar los pasos para compilar las imágenes y, luego, implementarlas en nuestro clúster de GKE.

Navega al menú de opciones y busca Cloud Deploy, que también se encuentra en la sección CI/CD del menú.

Aquí, verás dos canalizaciones: una para los servicios de backend y otra para las cargas de trabajo. Ambas implementan las imágenes en el mismo clúster de GKE, pero esto permite separar las implementaciones.

d2e4a659145ddf5e.png

IAM

Por último, consulta la página IAM en la consola de Cloud para verificar las cuentas de servicio que se crearon. Navega al menú de hamburguesa y busca IAM and Admin=>Service accounts. Debería verse algo similar a esto:

bed3d1af94974916.png

Terraform crea seis cuentas de servicio en total:

  • Es la cuenta de servicio de computadora predeterminada. No se usa en este codelab.
  • La cuenta cloudbuild-cicd se usa para los pasos de Cloud Build y Cloud Deploy.
  • Cuatro apps que usan nuestros servicios de backend para interactuar con Cloud Spanner.

A continuación, deberás configurar kubectl para interactuar con el clúster de GKE.

Configura kubectl

# Name of GKE cluster from terraform.tfvars file
export GKE_CLUSTER=sample-game-gke 

# get GKE credentials
gcloud container clusters get-credentials $GKE_CLUSTER --region us-central1

# Check that no errors occur
kubectl get serviceaccounts

Resultado del comando

#export GKE_CLUSTER=sample-game-gke

# gcloud container clusters get-credentials $GKE_CLUSTER --region us-central1
Fetching cluster endpoint and auth data.
kubeconfig entry generated for sample-game-gke.

# kubectl get serviceaccounts
NAME              SECRETS   AGE
default           0         37m
item-app          0         35m
matchmaking-app   0         35m
profile-app       0         35m
tradepost-app     0         35m

Resumen

¡Genial! Pudiste aprovisionar una instancia de Cloud Spanner, un clúster de GKE Autopilot, todo en una VPC para redes privadas.

Además, se crearon dos canalizaciones de Cloud Deploy para los servicios de backend y las cargas de trabajo, además de un repositorio de Artifact Registry para almacenar las imágenes compiladas.

Por último, se crearon y configuraron las cuentas de servicio para que funcionen con Workload Identity de modo que los servicios de backend puedan usar Cloud Spanner.

También tienes kubectl configurado para interactuar con el clúster de GKE en Cloud Shell después de implementar los servicios de backend y las cargas de trabajo.

Cuál es el próximo paso

Antes de que puedas usar los servicios, se debe definir el esquema de la base de datos. Lo configurarás a continuación.

4. Crea el esquema de la base de datos

Descripción general

Antes de que puedas ejecutar los servicios de backend, debes asegurarte de que el esquema de la base de datos esté implementado.

Si observas los archivos del directorio $DEMO_HOME/schema/migrations del repositorio de demostración, verás una serie de archivos .sql que definen nuestro esquema. Esto imita un ciclo de desarrollo en el que los cambios de esquema se rastrean en el propio repositorio y pueden vincularse a ciertas funciones de las aplicaciones.

Para este entorno de muestra, herramienta es la herramienta que aplicará nuestras migraciones de esquema con Cloud Build.

Cloud Build

En el archivo $DEMO_HOME/schema/cloudbuild.yaml, se describen los pasos que se seguirán:

serviceAccount: projects/${PROJECT_ID}/serviceAccounts/cloudbuild-cicd@${PROJECT_ID}.iam.gserviceaccount.com
steps:
- name: gcr.io/cloud-builders/curl
 id: fetch-wrench
 args: ['-Lo', '/workspace/wrench.tar.gz', 'https://github.com/cloudspannerecosystem/wrench/releases/download/v1.4.1/wrench-1.4.1-linux-amd64.tar.gz' ]

- name: gcr.io/cloud-builders/gcloud
 id: migrate-spanner-schema
 entrypoint: sh
 args:
 - '-xe'
 - '-c'
 - |
   tar -xzvf wrench.tar.gz

   chmod +x /workspace/wrench

   # Assumes only a single spanner instance and database. Fine for this demo in a dedicated project
   export SPANNER_PROJECT_ID=${PROJECT_ID}
   export SPANNER_INSTANCE_ID=$(gcloud spanner instances list | tail -n1 | awk '{print $1}')
   export SPANNER_DATABASE_ID=$(gcloud spanner databases list --instance=$$SPANNER_INSTANCE_ID | tail -n1 | awk '{print $1}')

   if [ -d ./migrations ]; then
     /workspace/wrench migrate up --directory .
   else
     echo "[Error] Missing migrations directory"
   fi
timeout: 600s

Básicamente, hay dos pasos:

  • descarga la llave inglesa en el lugar de trabajo de Cloud Build
  • ejecutar la migración de herramientas

Las variables de entorno de base de datos, instancia y proyecto de Spanner son necesarias para que la llave se conecte al extremo de escritura.

Cloud Build puede realizar estos cambios porque se ejecuta como la cuenta de servicio cloudbuild-cicd@${PROJECT_ID}.iam.gserviceaccount.com:

serviceAccount: projects/${PROJECT_ID}/serviceAccounts/cloudbuild-cicd@${PROJECT_ID}.iam.gserviceaccount.com

Y esta cuenta de servicio tiene el rol spanner.databaseUser agregado por Terraform, lo que permite que la cuenta de servicio actualice el DDL.

Migraciones de esquemas

Hay cinco pasos de migración que se realizan según los archivos del directorio $DEMO_HOME/schema/migrations. Este es un ejemplo del archivo 000001.sql que crea una tabla players y los índices:

CREATE TABLE players (
   playerUUID STRING(36) NOT NULL,
   player_name STRING(64) NOT NULL,
   email STRING(MAX) NOT NULL,
   password_hash BYTES(60) NOT NULL,
   created TIMESTAMP,
   updated TIMESTAMP,
   stats JSON,
   account_balance NUMERIC NOT NULL DEFAULT (0.00),
   is_logged_in BOOL,
   last_login TIMESTAMP,
   valid_email BOOL,
   current_game STRING(36)
) PRIMARY KEY (playerUUID);

CREATE UNIQUE INDEX PlayerAuthentication ON players(email) STORING(password_hash);
CREATE UNIQUE INDEX PlayerName ON players(player_name);
CREATE INDEX PlayerGame ON players(current_game);

Envía la migración del esquema

Para enviar la compilación a fin de realizar la migración del esquema, cambia al directorio schema y ejecuta el siguiente comando de gcloud:

cd $DEMO_HOME/schema
gcloud builds submit --config=cloudbuild.yaml

Resultado del comando

Creating temporary tarball archive of 8 file(s) totalling 11.2 KiB before compression.
Uploading tarball of [.] to [gs://(project)_cloudbuild/source/(snip).tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/(project)/locations/global/builds/7defe982-(snip)].
Logs are available at [ https://console.cloud.google.com/cloud-build/builds/7defe982-(snip)?project=(snip) ].

gcloud builds submit only displays logs from Cloud Storage. To view logs from Cloud Logging, run:
gcloud beta builds submit

ID: 7defe982-(snip)
CREATE_TIME: (created time)
DURATION: 3M11S
SOURCE: gs://(project)_cloudbuild/source/(snip).tgz
IMAGES: -
STATUS: SUCCESS

En el resultado anterior, notarás un vínculo con el proceso Created de Cloud Build. Si haces clic allí, te llevará a la compilación en la consola de Cloud para que puedas supervisar el progreso de la compilación y ver qué está haciendo.

11b1cf107876d797.png

Resumen

En este paso, usaste Cloud Build para enviar la migración inicial del esquema que aplicó 5 operaciones de DDL diferentes. Estas operaciones representan cuándo se agregaron atributos que requerían cambios en el esquema de la base de datos.

En una situación de desarrollo normal, se recomienda realizar cambios de esquema retrocompatibles con la aplicación actual para evitar interrupciones.

En el caso de los cambios que no son retrocompatibles, debes implementar los cambios en la aplicación y el esquema en etapas para garantizar que no haya interrupciones.

Cuál es el próximo paso

Con el esquema implementado, el siguiente paso es implementar los servicios de backend.

5. Implementa los servicios de backend

Descripción general

Los servicios de backend para este codelab son APIs de REST de golang que representan cuatro servicios diferentes:

  • Perfil: Proporciona a los jugadores la posibilidad de registrarse y autenticarse en nuestro "juego" de muestra.
  • Creación de partidas: Interactúa con los datos de los jugadores para ayudar con una función de creación de partidas, haz un seguimiento de la información sobre los juegos que se crean y actualiza las estadísticas de los jugadores cuando se cierran las partidas.
  • Elemento: Permite que los jugadores adquieran elementos y dinero durante el transcurso del juego.
  • Tradepost: Permite que los jugadores compren y vendan artículos de un punto de intercambio.

d36e958411d44b5d.png

Puedes obtener más información sobre estos servicios en el codelab Cómo comenzar a usar el desarrollo de juegos en Cloud Spanner. Para nuestros fines, queremos que estos servicios se ejecuten en nuestro clúster de GKE Autopilot.

Estos servicios deben poder modificar los datos de Spanner. Para ello, cada servicio tiene una cuenta de servicio creada que les otorga el rol 'databaseUser' en el área de la seguridad en la nube.

Workload Identity permite que una cuenta de servicio de Kubernetes actúe en nombre de de Google Cloud siguiendo estos pasos en Terraform:

  • Crear el recurso de cuenta de servicio de Google Cloud del servicio (GSA)
  • Asigna el rol databaseUser a esa cuenta de servicio
  • Asigna el rol workloadIdentityUser a esa cuenta de servicio
  • Crear una cuenta de servicio de Kubernetes (KSA) que haga referencia a la función de

Un diagrama aproximado se vería así:

a8662d31d66b5910.png

Terraform creó las cuentas de servicio y las cuentas de servicio de Kubernetes por ti. Además, puedes verificar las cuentas de servicio de Kubernetes con kubectl:

# kubectl get serviceaccounts
NAME              SECRETS   AGE
default           0         37m
item-app          0         35m
matchmaking-app   0         35m
profile-app       0         35m
tradepost-app     0         35m

La compilación funciona de la siguiente manera:

serviceAccount: projects/${PROJECT_ID}/serviceAccounts/cloudbuild-cicd@${PROJECT_ID}.iam.gserviceaccount.com
steps:

#
# Building of images
#
 - name: gcr.io/cloud-builders/docker
   id: profile
   args: ["build", ".", "-t", "${_PROFILE_IMAGE}"]
   dir: profile
   waitFor: ['-']
 - name: gcr.io/cloud-builders/docker
   id: matchmaking
   args: ["build", ".", "-t", "${_MATCHMAKING_IMAGE}"]
   dir: matchmaking
   waitFor: ['-']
 - name: gcr.io/cloud-builders/docker
   id: item
   args: ["build", ".", "-t", "${_ITEM_IMAGE}"]
   dir: item
   waitFor: ['-']
 - name: gcr.io/cloud-builders/docker
   id: tradepost
   args: ["build", ".", "-t", "${_TRADEPOST_IMAGE}"]
   dir: tradepost
   waitFor: ['-']

#
# Deployment
#
 - name: gcr.io/google.com/cloudsdktool/cloud-sdk
   id: cloud-deploy-release
   entrypoint: gcloud
   args:
     [
       "deploy", "releases", "create", "${_REL_NAME}",
       "--delivery-pipeline", "sample-game-services",
       "--skaffold-file", "skaffold.yaml",
       "--skaffold-version", "1.39",
       "--images", "profile=${_PROFILE_IMAGE},matchmaking=${_MATCHMAKING_IMAGE},item=${_ITEM_IMAGE},tradepost=${_TRADEPOST_IMAGE}",
       "--region", "us-central1"
     ]

artifacts:
 images:
   - ${_REGISTRY}/profile
   - ${_REGISTRY}/matchmaking
   - ${_REGISTRY}/item
   - ${_REGISTRY}/tradepost

substitutions:
 _PROFILE_IMAGE: ${_REGISTRY}/profile:${BUILD_ID}
 _MATCHMAKING_IMAGE: ${_REGISTRY}/matchmaking:${BUILD_ID}
 _ITEM_IMAGE: ${_REGISTRY}/item:${BUILD_ID}
 _TRADEPOST_IMAGE: ${_REGISTRY}/tradepost:${BUILD_ID}
 _REGISTRY: us-docker.pkg.dev/${PROJECT_ID}/spanner-game-images
 _REL_NAME: rel-${BUILD_ID:0:8}
options:
 dynamic_substitutions: true
 machineType: E2_HIGHCPU_8
 logging: CLOUD_LOGGING_ONLY
  • El comando de Cloud Build lee este archivo y sigue los pasos que se indican. Primero, compila las imágenes de servicio. Luego, ejecuta un comando gcloud deploy create. Esto lee el archivo $DEMO_HOME/backend_services/skaffold.yaml, que define dónde se encuentra cada archivo de implementación:
apiVersion: skaffold/v2beta29
kind: Config
deploy:
 kubectl:
   manifests:
     - spanner_config.yaml
     - profile/deployment.yaml
     - matchmaking/deployment.yaml
     - item/deployment.yaml
     - tradepost/deployment.yaml
  • Cloud Deploy seguirá las definiciones del archivo deployment.yaml de cada servicio. El archivo de implementación del servicio contiene la información para crear un servicio, que en este caso es un clusterIP que se ejecuta en el puerto 80.

El " ClusterIP" evita que los Pods del servicio de backend tengan una IP externa, de modo que solo las entidades que pueden conectarse a la red de GKE interna puedan acceder a los servicios de backend. Los jugadores no deben poder acceder directamente a estos servicios, ya que acceden a los datos de Spanner y los modifican.

apiVersion: v1
kind: Service
metadata:
 name: profile
spec:
 type: ClusterIP
 selector:
   app: profile
 ports:
 - port: 80
   targetPort: 80

Además de crear un Service de Kubernetes, Cloud Deploy también crea un Deployment de Kubernetes. Examinemos la sección de implementación del servicio profile:

---
apiVersion: apps/v1
kind: Deployment
metadata:
 name: profile
spec:
 replicas: 2 # EDIT: Number of instances of deployment
 selector:
   matchLabels:
     app: profile
 template:
   metadata:
     labels:
       app: profile
   spec:
     serviceAccountName: profile-app
     containers:
     - name: profile-service
       image: profile
       ports:
         - containerPort: 80
       envFrom:
         - configMapRef:
             name: spanner-config
       env:
         - name: SERVICE_HOST
           value: "0.0.0.0"
         - name: SERVICE_PORT
           value: "80"
       resources:
         requests:
           cpu: "1"
           memory: "1Gi"
           ephemeral-storage: "100Mi"
         limits:
           cpu: "1"
           memory: "1Gi"
           ephemeral-storage: "100Mi"

La parte superior proporciona algunos metadatos sobre el servicio. Lo más importante de esto es definir cuántas réplicas creará esta implementación.

replicas: 2 # EDIT: Number of instances of deployment

A continuación, veremos qué cuenta de servicio debe ejecutar la app y qué imagen debe usar. Estos coinciden con la cuenta de servicio de Kubernetes creada desde Terraform y la imagen creada durante el paso de Cloud Build.

spec:
  serviceAccountName: profile-app
  containers:
    - name: profile-service
      image: profile

Luego, especificamos información sobre las herramientas de redes y las variables de entorno.

spanner_config es un ConfigMap de Kubernetes que especifica la información del proyecto, la instancia y la base de datos necesaria para que la aplicación se conecte a Spanner.

apiVersion: v1
kind: ConfigMap
metadata:
  name: spanner-config
data:
  SPANNER_PROJECT_ID: ${project_id}
  SPANNER_INSTANCE_ID: ${instance_id}
  SPANNER_DATABASE_ID: ${database_id}
ports:
  - containerPort: 80
envFrom:
  - configMapRef:
    name: spanner-config
env:
  - name: SERVICE_HOST
    value: "0.0.0.0"
  - name: SERVICE_PORT
    value: "80"

SERVICE_HOST y SERVICE_PORT son variables de entorno adicionales que el servicio necesita para saber dónde realizar la vinculación.

En la última sección, se indica a GKE cuántos recursos hay que permitir para cada réplica en esta implementación. Esto también es lo que GKE Autopilot usa para escalar el clúster según sea necesario.

resources:
  requests:
    cpu: "1"
    memory: "1Gi"
    ephemeral-storage: "100Mi"
  limits:
    cpu: "1"
    memory: "1Gi"
    ephemeral-storage: "100Mi"

Con esta información, es hora de implementar los servicios de backend.

Implementa los servicios de backend

Como se mencionó, la implementación de los servicios de backend usa Cloud Build. Al igual que con las migraciones de esquemas, puedes enviar la solicitud de compilación con la línea de comandos de gcloud:

cd $DEMO_HOME/backend_services
gcloud builds submit --config=cloudbuild.yaml

Resultado del comando

Creating temporary tarball archive of 66 file(s) totalling 864.6 KiB before compression.
Uploading tarball of [.] to [gs://(project)_cloudbuild/source/(snip).tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/(project)/locations/global/builds/30207dd1-(snip)].
Logs are available at [ https://console.cloud.google.com/cloud-build/builds/30207dd1-(snip)?project=(snip) ].

gcloud builds submit only displays logs from Cloud Storage. To view logs from Cloud Logging, run:
gcloud beta builds submit

ID: 30207dd1-(snip)
CREATE_TIME: (created time)
DURATION: 3M17S
SOURCE: gs://(project)_cloudbuild/source/(snip).tgz
IMAGES: us-docker.pkg.dev/(project)/spanner-game-images/profile:30207dd1-(snip) (+3 more)
STATUS: SUCCESS

A diferencia del resultado del paso schema migration, el resultado de esta compilación indica que se crearon algunas imágenes. Se almacenarán en tu repositorio de Artifact Registry.

El resultado del paso gcloud build tendrá un vínculo a la consola de Cloud. Revísalos.

Una vez que recibas la notificación de éxito de Cloud Build, navega a Cloud Deploy y, luego, a la canalización sample-game-services para supervisar el progreso de la implementación.

df5c6124b9693986.png

Cuando los servicios se implementan, puedes verificar kubectl para ver los Pods estado:

kubectl get pods

Resultado del comando

NAME                           READY   STATUS    RESTARTS   AGE
item-6b9d5f678c-4tbk2          1/1     Running   0          83m
matchmaking-5bcf799b76-lg8zf   1/1     Running   0          80m
profile-565bbf4c65-kphdl       1/1     Running   0          83m
profile-565bbf4c65-xw74j       1/1     Running   0          83m
tradepost-68b87ccd44-gw55r     1/1     Running   0          79m

Luego, verifica los servicios para ver ClusterIP en acción:

kubectl get services

Resultado del comando

NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
item          ClusterIP   10.172.XXX.XXX   <none>        80/TCP    84m
kubernetes    ClusterIP   10.172.XXX.XXX   <none>        443/TCP   137m
matchmaking   ClusterIP   10.172.XXX.XXX   <none>        80/TCP    84m
profile       ClusterIP   10.172.XXX.XXX   <none>        80/TCP    84m
tradepost     ClusterIP   10.172.XXX.XXX   <none>        80/TCP    84m

También puedes navegar a la IU de GKE en la consola de Cloud para ver Workloads, Services y ConfigMaps.

Cargas de trabajo

da98979ae49e5a30.png

Servicios

406ca2fe7ad4818b.png

ConfigMaps

a0ebd34ee735ee11.png

3b9ef91c77a4e7f0.png

Resumen

En este paso, implementaste los cuatro servicios de backend en GKE Autopilot. Pudiste ejecutar el paso de Cloud Build y verificar el progreso en Cloud Deploy y en Kubernetes en la consola de Cloud.

También aprendiste cómo estos servicios usan Workload Identity para usar la identidad de una cuenta de servicio que tiene los permisos adecuados para leer y escribir datos en la base de datos de Spanner.

Próximos pasos

En la siguiente sección, implementarás las cargas de trabajo.

6. Implementa las cargas de trabajo

Descripción general

Ahora que los servicios de backend se están ejecutando en el clúster, implementarás las cargas de trabajo.

dd900485e2eeb611.png

Se puede acceder a las cargas de trabajo de forma externa, y hay una para cada servicio de backend a los fines de este codelab.

Estas cargas de trabajo son secuencias de comandos de generación de cargas basadas en Locust que imitan los patrones de acceso reales que esperan estos servicios de muestra.

Hay archivos para el proceso de Cloud Build:

  • $DEMO_HOME/workloads/cloudbuild.yaml (generado por Terraform)
  • $DEMO_HOME/workloads/skaffold.yaml
  • un archivo deployment.yaml para cada carga de trabajo

Los archivos de carga de trabajo deployment.yaml se ven un poco diferentes de los archivos de implementación del servicio de backend.

Este es un ejemplo de matchmaking-workload:

apiVersion: v1
kind: Service
metadata:
 name: matchmaking-workload
spec:
 type: LoadBalancer
 selector:
   app: matchmaking-workload
 ports:
 - port: 8089
   targetPort: 8089
---
apiVersion: apps/v1
kind: Deployment
metadata:
 name: matchmaking-workload
spec:
 replicas: 1 # EDIT: Number of instances of deployment
 selector:
   matchLabels:
     app: matchmaking-workload
 template:
   metadata:
     labels:
       app: matchmaking-workload
   spec:
     serviceAccountName: default
     containers:
     - name: matchmaking-workload
       image: matchmaking-workload
       ports:
         - containerPort: 8089
       resources:
         requests:
           cpu: "500m"
           memory: "512Mi"
           ephemeral-storage: "100Mi"
         limits:
           cpu: "500m"
           memory: "512Mi"
           ephemeral-storage: "100Mi"

La parte superior del archivo define el servicio. En este caso, se crea una LoadBalancer y la carga de trabajo se ejecuta en el puerto 8089.

El objeto LoadBalancer proporcionará una IP externa que se puede usar para conectarse a la carga de trabajo.

apiVersion: v1
kind: Service
metadata:
 name: matchmaking-workload
spec:
 type: LoadBalancer
 selector:
   app: matchmaking-workload
 ports:
 - port: 8089
   targetPort: 8089

La parte superior de la sección de implementación están en los metadatos sobre la carga de trabajo. En este caso, solo se está implementando una réplica:

replicas: 1 

Sin embargo, las especificaciones del contenedor son diferentes. Por un lado, usamos una cuenta de servicio de Kubernetes default. Esta cuenta no tiene ningún privilegio especial, ya que la carga de trabajo no necesita conectarse a ningún recurso de Google Cloud, excepto a los servicios de backend que se ejecutan en el clúster de GKE.

La otra diferencia es que no se necesitan variables de entorno para estas cargas de trabajo. El resultado es una especificación de implementación más corta.

spec:
  serviceAccountName: default
  containers:
    - name: matchmaking-workload
      image: matchmaking-workload
  ports:
    - containerPort: 8089

La configuración de recursos es similar a la de los servicios de backend. Recuerda que así es como GKE Autopilot sabe cuántos recursos se necesitan para satisfacer las solicitudes de todos los Pods que se ejecutan en el clúster.

Implementa las cargas de trabajo.

Implementa las cargas de trabajo

Al igual que antes, puedes enviar la solicitud de compilación con la línea de comandos de gcloud:

cd $DEMO_HOME/workloads
gcloud builds submit --config=cloudbuild.yaml

Resultado del comando

Creating temporary tarball archive of 18 file(s) totalling 26.2 KiB before compression.
Some files were not included in the source upload.

Check the gcloud log [/tmp/tmp.4Z9EqdPo6d/logs/(snip).log] to see which files and the contents of the
default gcloudignore file used (see `$ gcloud topic gcloudignore` to learn
more).

Uploading tarball of [.] to [gs://(project)_cloudbuild/source/(snip).tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/(project)/locations/global/builds/(snip)].
Logs are available at [ https://console.cloud.google.com/cloud-build/builds/0daf20f6-(snip)?project=(snip) ].

gcloud builds submit only displays logs from Cloud Storage. To view logs from Cloud Logging, run:
gcloud beta builds submit

ID: 0daf20f6-(snip)
CREATE_TIME: (created_time)
DURATION: 1M41S
SOURCE: gs://(project)_cloudbuild/source/(snip).tgz
IMAGES: us-docker.pkg.dev/(project)/spanner-game-images/profile-workload:0daf20f6-(snip) (+4 more)
STATUS: SUCCESS

Asegúrate de revisar los registros de Cloud Build y la canalización de Cloud Deploy en la consola de Cloud para verificar el estado. Para las cargas de trabajo, la canalización de Cloud Deploy es sample-game-workloads:

Cuando se complete la implementación, verifica el estado con kubectl en Cloud Shell:

kubectl get pods

Resultado del comando

NAME                                    READY   STATUS    RESTARTS   AGE
game-workload-7ff44cb657-pxxq2          1/1     Running   0          12m
item-6b9d5f678c-cr29w                   1/1     Running   0          9m6s
item-generator-7bb4f57cf8-5r85b         1/1     Running   0          12m
matchmaking-5bcf799b76-lg8zf            1/1     Running   0          117m
matchmaking-workload-76df69dbdf-jds9z   1/1     Running   0          12m
profile-565bbf4c65-kphdl                1/1     Running   0          121m
profile-565bbf4c65-xw74j                1/1     Running   0          121m
profile-workload-76d6db675b-kzwng       1/1     Running   0          12m
tradepost-68b87ccd44-gw55r              1/1     Running   0          116m
tradepost-workload-56c55445b5-b5822     1/1     Running   0          12m

Luego, verifica los servicios de carga de trabajo para ver LoadBalancer en acción:

kubectl get services 

Resultado del comando

NAME                   TYPE          CLUSTER-IP  EXTERNAL-IP     PORT(S)        AGE
game-workload          LoadBalancer  *snip*      35.XX.XX.XX   8089:32483/TCP   12m
item                   ClusterIP     *snip*      <none>         80/TCP          121m
item-generator         LoadBalancer  *snip*      34.XX.XX.XX   8089:32581/TCP   12m
kubernetes             ClusterIP     *snip*      <none>          443/TCP        174m
matchmaking            ClusterIP     *snip*      <none>          80/TCP         121m
matchmaking-workload   LoadBalancer  *snip*      34.XX.XX.XX   8089:31735/TCP   12m
profile                ClusterIP     *snip*      <none>          80/TCP         121m
profile-workload       LoadBalancer  *snip*      34.XX.XX.XX   8089:32532/TCP   12m
tradepost              ClusterIP     *snip*      <none>          80/TCP         121m
tradepost-workload     LoadBalancer  *snip*      34.XX.XX.XX   8089:30002/TCP   12m

Resumen

Ya implementaste las cargas de trabajo en el clúster de GKE. Estas cargas de trabajo no requieren permisos de IAM adicionales y son accesibles de forma externa en el puerto 8089 con el servicio LoadBalancer.

Próximos pasos

Con los servicios de backend y las cargas de trabajo en ejecución, es hora de “jugar” el partido.

7. Comienza a jugar

Descripción general

Los servicios de backend para tu “juego” de muestra ahora se están ejecutando, y también tienes los medios para generar "jugadores" que interactúan con esos servicios mediante las cargas de trabajo.

Cada carga de trabajo usa Locust para simular una carga real en las APIs de servicio. En este paso, ejecutarás varias de las cargas de trabajo para generar carga en el clúster de GKE y en Spanner, además de almacenar datos en Spanner.

Esta es una descripción de cada carga de trabajo:

  • La carga de trabajo item-generator es una carga de trabajo rápida para generar una lista de game_items que los jugadores pueden adquirir durante el proceso de "jugar" el partido.
  • El objeto profile-workload simula que los jugadores se registran y acceden.
  • El objeto matchmaking-workload simula a los jugadores que esperan una cola para asignarlos a los juegos.
  • El objeto game-workload simula jugadores que adquieren elementos del juego y dinero durante el transcurso del juego.
  • El objeto tradepost-workload simula que los jugadores pueden vender y comprar artículos en el centro de operaciones.

En este codelab, se destacará la ejecución específica de item-generator y profile-workload.

Ejecuta el generador de elementos

item-generator usa el extremo del servicio de backend item para agregar game_items a Spanner. Estos elementos son necesarios para que game-workload y tradepost-workload funcionen correctamente.

El primer paso es obtener la IP externa del servicio item-generator. En Cloud Shell, ejecuta lo siguiente:

# The external IP is the 4th column of the output
kubectl get services | grep item-generator | awk '{print $4}'

Resultado del comando

{ITEMGENERATOR_EXTERNAL_IP}

Ahora, abre una nueva pestaña del navegador y apúntala a http://{ITEMGENERATOR_EXTERNAL_IP}:8089. Deberías ver una página como esta:

817307157d66c661.png

Dejarás users y spawn en el valor predeterminado 1. Para host, ingresa http://item. Haz clic en las opciones avanzadas y, luego, ingresa 10s para la duración.

A continuación, se muestra cómo debería verse la configuración:

f3143165c6285c21.png

Haz clic en "Start swarming".

Las estadísticas comenzarán a mostrarse para las solicitudes que se emitan en el extremo POST /items. Después de 10 segundos, se detendrá la carga.

Haz clic en Charts y verás algunos gráficos sobre el rendimiento de estas solicitudes.

abad0a9f3c165345.png

Ahora, debes verificar si los datos se ingresaron en la base de datos de Spanner.

Para ello, haz clic en el menú de opciones y navega a “Spanner”. Desde esta página, navega a sample-instance y sample-database. Luego, haz clic en "Query".

Queremos seleccionar la cantidad de game_items:

SELECT COUNT(*) FROM game_items;

En la parte inferior, verás el resultado.

137ce291a2ff2706.png

No necesitamos mucha cantidad inicial de game_items. Pero ahora están disponibles para que los jugadores los adquieran.

Ejecuta la carga de trabajo de perfil

Con tu elemento inicial de game_items, el siguiente paso es lograr que los jugadores se registren para poder jugar.

profile-workload usará Locust para simular que los jugadores crean cuentas, acceden, recuperan la información del perfil y cierran la sesión. Todas estas pruebas prueban los extremos del servicio de backend profile en una carga de trabajo típica similar a la de producción.

Para ejecutarlo, obtén la IP externa de profile-workload:

# The external IP is the 4th column of the output
kubectl get services | grep profile-workload | awk '{print $4}'

Resultado del comando

{PROFILEWORKLOAD_EXTERNAL_IP}

Ahora, abre una nueva pestaña del navegador y apúntala a http://{PROFILEWORKLOAD_EXTERNAL_IP}:8089. Deberías ver una página de Locust similar a la anterior.

En este caso, usarás http://profile para el host. Y no especificarás un tiempo de ejecución en las opciones avanzadas. Además, especifica users para que sea 4, lo que simulará 4 solicitudes de usuario a la vez.

La prueba profile-workload debería verse de la siguiente manera:

f6e0f06efb0ad6e.png

Haz clic en "Start swarming".

Al igual que antes, comenzarán a mostrarse las estadísticas de los distintos extremos de REST profile. Haz clic en los gráficos para ver una vista del rendimiento de todo.

4c2146e1cb3de23e.png

Resumen

En este paso, generaste algunas game_items y, luego, consultaste la tabla game_items con la IU de consulta de Spanner en la consola de Cloud.

También permitiste que los jugadores se registraran en tu juego y viste cómo Locust puede crear cargas de trabajo similares a las de producción en tus servicios de backend.

Próximos pasos

Después de ejecutar las cargas de trabajo, comprueba cómo se comportan el clúster de GKE y la instancia de Spanner.

8. Revisa el uso de GKE y Spanner

Con el servicio de perfil en ejecución, es momento de aprovechar la oportunidad para ver cómo se comportan tu clúster de GKE Autopilot y Cloud Spanner.

Verifica el clúster de GKE

Navega al clúster de Kubernetes. Ten en cuenta que, desde que implementaste las cargas de trabajo y los servicios, el clúster ahora tiene algunos detalles agregados sobre el total de CPU virtuales y memoria. Esta información no estaba disponible cuando no había cargas de trabajo en el clúster.

61d2d766c1f10079.png

Ahora, haz clic en el clúster sample-game-gke y cambia a la pestaña de observabilidad:

fa9acc7e26ea04a.png

El espacio de nombres de Kubernetes default debería haber superado el espacio de nombres kube-system en cuanto al uso de CPU, ya que nuestras cargas de trabajo y servicios de backend se ejecutan en default. Si no es así, asegúrate de que profile workload aún se esté ejecutando y espera unos minutos para que se actualicen los gráficos.

Para ver qué cargas de trabajo consumen más recursos, ve al panel de Workloads.

En lugar de ir a cada carga de trabajo de forma individual, ve directamente a la pestaña Observabilidad del panel. Deberías ver que las CPU de profile y profile-workload aumentaron.

f194b618969cfa9e.png

Ahora, revisa Cloud Spanner.

Verifica la instancia de Cloud Spanner

Para verificar el rendimiento de Cloud Spanner, navega a Spanner y haz clic en la instancia sample-instance y la base de datos sample-game.

Allí, verás la pestaña System Insights en el menú de la izquierda:

216212182a57dfd1.png

Aquí hay muchos gráficos que te ayudarán a comprender el rendimiento general de tu instancia de Spanner, incluidos CPU utilization, transaction latency and locking y query throughput.

Además de Estadísticas del sistema, puedes obtener información más detallada sobre la carga de trabajo de las consultas a través de los otros vínculos de la sección Observabilidad:

  • Las estadísticas de consultas ayudan a identificar las consultas topN que usan recursos en Spanner.
  • Las estadísticas de transacción y bloqueo ayudan a identificar transacciones con latencias altas.
  • Key Visualizer ayuda a visualizar los patrones de acceso y a buscar hotspots en los datos.

Resumen

En este paso, aprendiste a verificar algunas métricas de rendimiento básicas para GKE Autopilot y Spanner.

Por ejemplo, con la carga de trabajo de tu perfil en ejecución, consulta la tabla players para obtener más información sobre los datos que se almacenan allí.

Próximos pasos

A continuación, es hora de limpiar.

9. Realice una limpieza

Antes de realizar la limpieza, puedes explorar las otras cargas de trabajo que no abarcaste. Específicamente, matchmaking-workload, game-workload y tradepost-workload.

Cuando hayas terminado de reproducir el juego, puedes limpiar el área de juegos. Por suerte, esto es bastante fácil.

Primero, si tu profile-workload aún se ejecuta en el navegador, detenla:

13ae755a11f3228.png

Haz lo mismo con cada carga de trabajo que hayas probado.

Luego, en Cloud Shell, navega a la carpeta de infraestructura. Usarás destroy para ejecutar la infraestructura con Terraform:

cd $DEMO_HOME/infrastructure
terraform destroy
# type 'yes' when asked

Resultado del comando

Plan: 0 to add, 0 to change, 46 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

*snip*

Destroy complete! Resources: 46 destroyed.

En la consola de Cloud, navega a Spanner, Kubernetes Cluster, Artifact Registry, Cloud Deploy y IAM para validar que se quitaron todos los recursos.

10. ¡Felicitaciones!

¡Felicitaciones! Implementaste correctamente aplicaciones de muestra de Golang en GKE Autopilot y las conectaste a Cloud Spanner con Workload Identity.

Como ventaja adicional, esta infraestructura se configuró y quitó fácilmente de forma repetible con Terraform.

Puedes obtener más información sobre los servicios de Google Cloud con los que interactuaste en este codelab:

Próximos pasos

Ahora que tienes una comprensión básica de cómo GKE Autopilot y Cloud Spanner pueden trabajar en conjunto, ¿por qué no dar el siguiente paso y comenzar a compilar tu propia aplicación para trabajar con estos servicios?