Como conectar o Cloud Spanner ao Autopilot do GKE

1. Introdução

O Cloud Spanner é um serviço de banco de dados relacional totalmente gerenciado, horizontalmente escalonável e distribuído globalmente que fornece transações ACID e semântica SQL sem deixar de oferecer desempenho e alta disponibilidade.

O GKE Autopilot é um modo de operação no GKE em que o Google gerencia a configuração do cluster, incluindo nós, escalonamento, segurança e outras configurações predefinidas para seguir as práticas recomendadas. Por exemplo, o GKE Autopilot ativa a Identidade da carga de trabalho para gerenciar permissões de serviço.

O objetivo deste laboratório é orientar você no processo de conexão de vários serviços de back-end em execução no Autopilot do GKE a um banco de dados do Cloud Spanner.

3d810aa9ec80a271.png

Neste laboratório, você vai configurar um projeto e iniciar o Cloud Shell. Em seguida, você vai implantar a infraestrutura usando o Terraform.

Quando isso terminar, você vai interagir com o Cloud Build e o Cloud Deploy para realizar uma migração inicial de esquema para o banco de dados de jogos, implantar os serviços de back-end e, em seguida, implantar as cargas de trabalho.

Os serviços neste codelab são os mesmos do codelab Introdução ao Cloud Spanner para desenvolvimento de jogos. Não é necessário fazer esse codelab para executar os serviços no GKE e se conectar ao Spanner. Mas se você quiser mais detalhes sobre os serviços que funcionam no Spanner, confira.

Com as cargas de trabalho e os serviços de back-end em execução, é possível começar a gerar carga e observar como os serviços funcionam juntos.

Por fim, você vai limpar os recursos criados neste laboratório.

O que você vai criar

Neste laboratório, você vai:

  • Provisionar a infraestrutura usando o Terraform
  • Criar o esquema do banco de dados usando um processo de migração de esquema no Cloud Build
  • Implante os quatro serviços de back-end do Go que usam a Identidade da carga de trabalho para se conectar ao Cloud Spanner.
  • Implante os quatro serviços de carga de trabalho usados para simular a carga dos serviços de back-end.

O que você vai aprender

  • Como provisionar pipelines do Autopilot do GKE, do Cloud Spanner e do Cloud Deploy usando o Terraform
  • Como a Identidade da carga de trabalho permite que os serviços no GKE representem contas de serviço para acessar as permissões do IAM e trabalhar com o Cloud Spanner
  • Como gerar carga semelhante à de produção no GKE e no Cloud Spanner usando o Locust.io

O que é necessário

  • Um projeto na nuvem do Google Cloud conectado a uma conta de faturamento.
  • Um navegador, como o Chrome ou o Firefox

2. Configuração e requisitos

Criar um projeto

Se você ainda não tem uma Conta do Google (Gmail ou Google Apps), crie uma. Faça login no Console do Google Cloud Platform ( console.cloud.google.com) e crie um novo projeto.

Se você já tiver um projeto, clique no menu suspenso de seleção no canto superior esquerdo do console:

6c9406d9b014760.png

e clique no botão NEW PROJECT na caixa de diálogo exibida para criar um projeto:

949d83c8a4ee17d9.png

Se você ainda não tiver um projeto, uma caixa de diálogo como esta será exibida para criar seu primeiro:

870a3cbd6541ee86.png

A caixa de diálogo de criação de projeto subsequente permite que você insira os detalhes do novo projeto:

6a92c57d3250a4b3.png

Lembre-se do código do projeto, um nome exclusivo em todos os projetos do Google Cloud. O nome acima já foi escolhido e não servirá para você. Faremos referência a ele mais adiante neste codelab como PROJECT_ID.

Em seguida, será preciso ativar o faturamento no Developers Console para usar os recursos do Google Cloud e ativar a API Cloud Spanner, caso ainda não tenha feito isso.

15d0ef27a8fbab27.png

A execução por meio deste codelab terá um custo baixo, mas poderá ser mais se você decidir usar mais recursos ou se deixá-los em execução. Consulte a seção "limpeza" no final deste documento. Os preços do Google Cloud Spanner estão documentados neste link, e o Autopilot do GKE está documentado neste link.

Novos usuários do Google Cloud Platform estão qualificados para uma avaliação sem custo financeiro de US$300, o que torna este codelab totalmente sem custo financeiro.

Configuração do Cloud Shell

Embora o Google Cloud e o Spanner possam ser operados remotamente do seu laptop, neste codelab usaremos o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.

O Cloud Shell é uma máquina virtual com base em Debian que contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Isso significa que tudo que você precisa para este codelab é um navegador (sim, funciona em um Chromebook).

  1. Para ativar o Cloud Shell no Console do Cloud, basta clicar em Ativar o Cloud Shell gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A. Leva apenas alguns instantes para provisionar e se conectar ao ambiente.

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

Screen Shot 2017-06-14 às 10.13.43 PM.png

Depois de se conectar ao Cloud Shell, você já estará autenticado e o projeto estará configurado com seu PROJECT_ID.

gcloud auth list

Resposta ao comando

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

Resposta ao comando

[core]
project = <PROJECT_ID>

Se, por algum motivo, o projeto não estiver definido, basta emitir o seguinte comando:

gcloud config set project <PROJECT_ID>

Quer encontrar seu PROJECT_ID? Veja qual ID você usou nas etapas de configuração ou procure-o no painel do Console do Cloud:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

O Cloud Shell também define algumas variáveis de ambiente por padrão, o que pode ser útil ao executar comandos futuros.

echo $GOOGLE_CLOUD_PROJECT

Resposta ao comando

<PROJECT_ID>

Fazer o download do código

No Cloud Shell, faça o download do código deste laboratório:

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

Resposta ao comando

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

Este codelab é baseado na versão v0.1.3. Confira essa tag:

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

Resposta ao comando

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

Agora, defina o diretório de trabalho atual como a variável de ambiente DEMO_HOME. Isso facilita a navegação enquanto você trabalha nas diferentes partes do codelab.

export DEMO_HOME=$(pwd)

Resumo

Nesta etapa, você configurou um novo projeto, ativou o Cloud Shell e fez o download do código deste laboratório.

A seguir

Em seguida, você vai provisionar a infraestrutura usando o Terraform.

3. provisione a infraestrutura

Visão geral

Com o projeto pronto, é hora de colocar a infraestrutura em funcionamento. Isso inclui rede VPC, Cloud Spanner, GKE Autopilot, Artifact Registry para armazenar as imagens que serão executadas no GKE, os pipelines do Cloud Deploy para os serviços e cargas de trabalho de back-end e, por fim, as contas de serviço e os privilégios do IAM para usar esses serviços.

É muita coisa. Felizmente, o Terraform pode simplificar essa configuração. O Terraform é uma ferramenta de "infraestrutura como código" que permite especificar o que precisamos para este projeto em uma série de arquivos ".tf". Isso simplifica o provisionamento da infraestrutura.

Não é necessário conhecer o Terraform para concluir este codelab. Mas se você quiser saber o que as próximas etapas estão fazendo, confira o que é criado nesses arquivos localizados no diretório infrastructure:

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

Configurar o Terraform

No Cloud Shell, mude para o diretório infrastructure e inicialize o Terraform:

cd $DEMO_HOME/infrastructure
terraform init

Resposta ao 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.

Em seguida, configure o Terraform copiando o terraform.tfvars.sample e modificando o valor do projeto. As outras variáveis também podem ser alteradas, mas o projeto é a única que precisa ser modificada para funcionar no seu ambiente.

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

Provisionar a infraestrutura

Agora é hora de provisionar a infraestrutura.

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

Resposta ao 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.

Verificar o que foi criado

Para verificar o que foi criado, confira os produtos no console do Cloud.

Cloud Spanner

Primeiro, verifique o Cloud Spanner navegando até o menu de navegação e clicando em Spanner. Talvez seja necessário clicar em "Ver mais produtos" para encontrar o item na lista.

Isso vai direcionar você para a lista de instâncias do Spanner. Clique na instância para ver os bancos de dados. O código será semelhante a este:

10b7fc0c4a86c59.png

Autopilot do GKE

Em seguida, confira o GKE navegando até o menu de hambúrguer e clicando em Kubernetes Engine => Clusters. Aqui você verá o cluster sample-games-gke em execução no modo Autopilot.

9cecb1a702e6b7ff.png

Artifact Registry

Agora, confira onde as imagens serão armazenadas. Clique no menu de navegação e encontre Artifact Registry=>Repositories. O Artifact Registry está na seção "CI/CD" do menu.

Lá, você vai encontrar um registro do Docker chamado spanner-game-images. Por enquanto, ele vai ficar vazio.

3f805eee312841b.png

Cloud Deploy

O Cloud Deploy é onde os pipelines foram criados para que o Cloud Build pudesse fornecer etapas para criar as imagens e implantá-las no cluster do GKE.

Navegue até o menu de navegação e encontre Cloud Deploy, que também está na seção CI/CD do menu.

Você vai notar dois pipelines: um para serviços de back-end e outro para cargas de trabalho. Ambos implantam as imagens no mesmo cluster do GKE, mas isso permite separar nossas implantações.

d2e4a659145ddf5e.png

IAM

Por fim, confira a página do IAM no Console do Cloud para verificar as contas de serviço criadas. Navegue até o menu de três traços e encontre IAM and Admin=>Service accounts. O código será semelhante a este:

bed3d1af94974916.png

O Terraform cria seis contas de serviço no total:

  • A conta de serviço padrão do computador. Não é usado neste codelab.
  • A conta cloudbuild-cicd é usada para as etapas do Cloud Build e do Cloud Deploy.
  • Quatro contas de "app" usadas pelos nossos serviços de back-end para interagir com o Cloud Spanner.

Em seguida, configure o kubectl para interagir com o cluster do GKE.

Configurar o 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

Resposta ao 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

Resumo

Ótimo! Você provisionou uma instância do Cloud Spanner e um cluster do GKE Autopilot, tudo em uma VPC para rede particular.

Além disso, dois pipelines do Cloud Deploy foram criados para os serviços de back-end e as cargas de trabalho, bem como um repositório do Artifact Registry para armazenar as imagens criadas.

Por fim, as contas de serviço foram criadas e configuradas para funcionar com a Identidade da carga de trabalho, para que os serviços de back-end possam usar o Cloud Spanner.

Você também precisa ter o kubectl configurado para interagir com o cluster do GKE no Cloud Shell depois de implantar os serviços e as cargas de trabalho de back-end.

A seguir

Antes de usar os serviços, é necessário definir o esquema do banco de dados. Você vai configurar isso em seguida.

4. Criar o esquema do banco de dados

Visão geral

Antes de executar os serviços de back-end, verifique se o esquema do banco de dados está no lugar.

Se você analisar os arquivos no diretório $DEMO_HOME/schema/migrations do repositório de demonstração, vai encontrar uma série de arquivos .sql que definem nosso esquema. Isso imita um ciclo de desenvolvimento em que as mudanças de esquema são rastreadas no próprio repositório e podem ser vinculadas a determinados recursos dos aplicativos.

Para este ambiente de exemplo, wrench é a ferramenta que vai aplicar nossas migrações de esquema usando o Cloud Build.

Cloud Build

O arquivo $DEMO_HOME/schema/cloudbuild.yaml descreve as etapas que serão realizadas:

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

Há basicamente duas etapas:

  • Faça o download da chave para o espaço de trabalho do Cloud Build.
  • executar a migração da chave

As variáveis de ambiente do projeto, da instância e do banco de dados do Spanner são necessárias para que o wrench se conecte ao endpoint de gravação.

O Cloud Build pode fazer essas mudanças porque está sendo executado como a conta de serviço cloudbuild-cicd@${PROJECT_ID}.iam.gserviceaccount.com:

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

Essa conta de serviço tem o papel spanner.databaseUser adicionado pelo Terraform, o que permite que ela atualize o DDL.

Migrações de esquema

Há cinco etapas de migração que são realizadas com base nos arquivos no diretório $DEMO_HOME/schema/migrations. Confira um exemplo do arquivo 000001.sql que cria uma tabela e índices players:

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);

Enviar a migração de esquema

Para enviar o build e realizar a migração do esquema, mude para o diretório schema e execute o seguinte comando gcloud:

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

Resposta ao 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

Na saída acima, você vai notar um link para o processo de build na nuvem Created. Se você clicar nele, vai acessar o build no Console do Cloud para monitorar o progresso e ver o que ele está fazendo.

11b1cf107876d797.png

Resumo

Nesta etapa, você usou o Cloud Build para enviar a migração inicial de esquema que aplicou cinco operações diferentes de DDL. Essas operações representam quando foram adicionados recursos que precisavam de mudanças no esquema do banco de dados.

Em um cenário de desenvolvimento normal, é recomendável fazer mudanças no esquema que sejam compatíveis com versões anteriores do aplicativo atual para evitar interrupções.

Para mudanças que não são compatíveis com versões anteriores, implante as mudanças no aplicativo e no esquema em etapas para garantir que não haja interrupções.

A seguir

Com o esquema no lugar, a próxima etapa é implantar os serviços de back-end.

5. Implantar os serviços de back-end

Visão geral

Os serviços de back-end deste codelab são APIs REST em Go que representam quatro serviços diferentes:

  • Perfil:permite que os jogadores se inscrevam e se autentiquem no nosso "jogo" de exemplo.
  • Matchmaking:interaja com os dados dos jogadores para ajudar com uma função de matchmaking, rastreie informações sobre os jogos criados e atualize as estatísticas dos jogadores quando os jogos forem fechados.
  • Item:permite que os jogadores adquiram itens e dinheiro do jogo ao longo da partida.
  • Posto de troca:permite que os jogadores comprem e vendam itens em um posto de troca.

d36e958411d44b5d.png

Saiba mais sobre esses serviços no codelab Introdução ao desenvolvimento de jogos com o Cloud Spanner. Para nossos fins, queremos que esses serviços sejam executados no cluster do Autopilot do GKE.

Esses serviços precisam poder modificar dados do Spanner. Para isso, cada serviço tem uma conta de serviço criada que concede a ele a função "databaseUser".

A Identidade da carga de trabalho permite que uma conta de serviço do Kubernetes personifique a conta de serviço do Google Cloud dos serviços seguindo estas etapas no Terraform:

  • Crie o recurso da conta de serviço do Google Cloud do serviço (GSA).
  • Atribua o papel databaseUser a essa conta de serviço.
  • Atribua o papel workloadIdentityUser a essa conta de serviço.
  • Crie uma conta de serviço do Kubernetes (KSA) que faça referência à GSA.

Um diagrama aproximado seria assim:

a8662d31d66b5910.png

O Terraform criou as contas de serviço e as contas de serviço do Kubernetes para você. Você pode verificar as contas de serviço do Kubernetes usando 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

O processo de build funciona da seguinte maneira:

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
  • O comando do Cloud Build lê esse arquivo e segue as etapas listadas. Primeiro, ele cria as imagens de serviço. Em seguida, ele executa um comando gcloud deploy create. Isso lê o arquivo $DEMO_HOME/backend_services/skaffold.yaml, que define onde cada arquivo de implantação está localizado:
apiVersion: skaffold/v2beta29
kind: Config
deploy:
 kubectl:
   manifests:
     - spanner_config.yaml
     - profile/deployment.yaml
     - matchmaking/deployment.yaml
     - item/deployment.yaml
     - tradepost/deployment.yaml
  • O Cloud Deploy vai seguir as definições do arquivo deployment.yaml de cada serviço. O arquivo de implantação do serviço contém as informações para criar um serviço, que, neste caso, é um clusterIP executado na porta 80.

O tipo " ClusterIP" impede que os pods de serviço de back-end tenham um IP externo. Assim, apenas entidades que podem se conectar à rede interna do GKE têm acesso aos serviços de back-end. Esses serviços não podem ser acessados diretamente pelos jogadores porque acessam e modificam os dados do Spanner.

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

Além de criar um serviço do Kubernetes, o Cloud Deploy também cria uma implantação do Kubernetes. Vamos examinar a seção de implantação do serviço 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"

A parte de cima fornece alguns metadados sobre o serviço. O mais importante aqui é definir quantas réplicas serão criadas por essa implantação.

replicas: 2 # EDIT: Number of instances of deployment

Em seguida, vemos qual conta de serviço deve executar o app e qual imagem ela deve usar. Elas correspondem à conta de serviço do Kubernetes criada com o Terraform e à imagem criada durante a etapa do Cloud Build.

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

Depois disso, especificamos algumas informações sobre variáveis de rede e ambiente.

O spanner_config é um ConfigMap do Kubernetes que especifica as informações de projeto, instância e banco de dados necessárias para que o aplicativo se conecte ao 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 e SERVICE_PORT são variáveis de ambiente adicionais necessárias para que o serviço saiba onde fazer a vinculação.

A seção final informa ao GKE quantos recursos permitir para cada réplica nessa implantação. É isso que o GKE Autopilot usa para escalonar o cluster conforme necessário.

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

Com essas informações, é hora de implantar os serviços de back-end.

Implantar os serviços de back-end

Como mencionado, a implantação dos serviços de back-end usa o Cloud Build. Assim como nas migrações de esquema, é possível enviar a solicitação de build usando a linha de comando gcloud:

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

Resposta ao 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

Ao contrário da saída da etapa schema migration, a saída desse build indica que algumas imagens foram criadas. Eles serão armazenados no repositório do Artifact Registry.

A saída da etapa gcloud build terá um link para o console do Cloud. Confira.

Depois de receber a notificação de sucesso do Cloud Build, navegue até o Cloud Deploy e depois até o pipeline sample-game-services para monitorar o progresso da implantação.

df5c6124b9693986.png

Depois que os serviços forem implantados, verifique kubectl para conferir o status dos pods:

kubectl get pods

Resposta ao 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

Em seguida, verifique os serviços para ver o ClusterIP em ação:

kubectl get services

Resposta ao 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

Você também pode acessar a interface do GKE no console do Cloud para ver os Workloads, Services e ConfigMaps.

Cargas de trabalho

da98979ae49e5a30.png

Serviços

406ca2fe7ad4818b.png

ConfigMaps

a0ebd34ee735ee11.png

3b9ef91c77a4e7f0.png

Resumo

Nesta etapa, você implantou os quatro serviços de back-end no GKE Autopilot. Você conseguiu executar a etapa do Cloud Build e verificar o progresso no Cloud Deploy e no Kubernetes no Console do Cloud.

Você também aprendeu como esses serviços usam a Identidade da carga de trabalho para representar uma conta de serviço com as permissões certas para ler e gravar dados no banco de dados do Spanner.

Próximas etapas

Na próxima seção, você vai implantar as cargas de trabalho.

6. Implantar as cargas de trabalho

Visão geral

Agora que os serviços de back-end estão em execução no cluster, implante as cargas de trabalho.

dd900485e2eeb611.png

As cargas de trabalho são acessíveis externamente, e há uma para cada serviço de back-end para fins deste codelab.

Essas cargas de trabalho são scripts de geração de carga baseados em Locust que imitam padrões de acesso reais esperados por esses serviços de exemplo.

Há arquivos para o processo de build do Cloud Build:

  • $DEMO_HOME/workloads/cloudbuild.yaml (gerado pelo Terraform)
  • $DEMO_HOME/workloads/skaffold.yaml
  • um arquivo deployment.yaml para cada carga de trabalho

Os arquivos da carga de trabalho deployment.yaml são um pouco diferentes dos arquivos de implantação do serviço de back-end.

Confira um exemplo do 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"

A parte de cima do arquivo define o serviço. Nesse caso, um LoadBalancer é criado, e a carga de trabalho é executada na porta 8089.

O LoadBalancer vai fornecer um IP externo que pode ser usado para se conectar à carga de trabalho.

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

A parte de cima da seção de implantação são os metadados sobre a carga de trabalho. Neste caso, apenas uma réplica está sendo implantada:

replicas: 1 

No entanto, a especificação do contêiner é diferente. Por exemplo, estamos usando uma conta de serviço do Kubernetes default. Essa conta não tem privilégios especiais, já que a carga de trabalho não precisa se conectar a nenhum recurso do Google Cloud, exceto os serviços de back-end em execução no cluster do GKE.

A outra diferença é que não há variáveis de ambiente necessárias para essas cargas de trabalho. O resultado é uma especificação de implantação mais curta.

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

As configurações de recursos são semelhantes às dos serviços de back-end. Lembre-se de que é assim que o GKE Autopilot sabe quantos recursos são necessários para atender às solicitações de todos os pods em execução no cluster.

Implante as cargas de trabalho.

Implantar as cargas de trabalho

Assim como antes, é possível enviar a solicitação de build usando a linha de comando gcloud:

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

Resposta ao 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

Verifique os registros do Cloud Build e o pipeline do Cloud Deploy no Cloud Console para conferir o status. Para as cargas de trabalho, o pipeline do Cloud Deploy é sample-game-workloads:

Depois que a implantação for concluída, verifique o status com kubectl no Cloud Shell:

kubectl get pods

Resposta ao 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

Em seguida, verifique os serviços de carga de trabalho para ver o LoadBalancer em ação:

kubectl get services 

Resposta ao 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

Resumo

Agora você implantou as cargas de trabalho no cluster do GKE. Essas cargas de trabalho não exigem outras permissões do IAM e podem ser acessadas externamente na porta 8089 usando o serviço LoadBalancer.

Próximas etapas

Com os serviços de back-end e as cargas de trabalho em execução, é hora de jogar.

7. Comece a jogar

Visão geral

Os serviços de back-end do seu "jogo" de exemplo estão em execução, e você também tem como gerar "jogadores" que interagem com esses serviços usando as cargas de trabalho.

Cada carga de trabalho usa o Locust para simular a carga real nas APIs de serviço. Nesta etapa, você vai executar várias cargas de trabalho para gerar carga no cluster do GKE e no Spanner, além de armazenar dados no Spanner.

Confira uma descrição de cada carga de trabalho:

  • A carga de trabalho item-generator é rápida para gerar uma lista de game_items que os jogadores podem adquirir ao "jogar".
  • O profile-workload simula jogadores se inscrevendo e fazendo login.
  • O matchmaking-workload simula jogadores entrando na fila para serem atribuídos a jogos.
  • O game-workload simula jogadores adquirindo game_items e dinheiro ao longo do jogo.
  • O tradepost-workload simula a capacidade dos jogadores de vender e comprar itens no posto de troca.

Este codelab vai destacar especificamente a execução do item-generator e do profile-workload.

Executar o gerador de itens

O item-generator usa o endpoint do serviço de back-end item para adicionar game_items ao Spanner. Esses itens são necessários para que o game-workload e o tradepost-workload funcionem corretamente.

A primeira etapa é conseguir o IP externo do serviço item-generator. No Cloud Shell, execute o seguinte:

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

Resposta ao comando

{ITEMGENERATOR_EXTERNAL_IP}

Agora, abra uma nova guia do navegador e acesse http://{ITEMGENERATOR_EXTERNAL_IP}:8089. Você vai acessar uma página como esta:

817307157d66c661.png

Você vai deixar users e spawn no valor padrão 1. Para o host, insira http://item. Clique nas opções avançadas e insira 10s como o tempo de execução.

Veja como a configuração deve ficar:

f3143165c6285c21.png

Clique em "Iniciar swarming".

As estatísticas vão começar a aparecer para as solicitações emitidas no endpoint POST /items. Após 10 segundos, o carregamento será interrompido.

Clique em Charts para ver alguns gráficos sobre o desempenho dessas solicitações.

abad0a9f3c165345.png

Agora, verifique se os dados foram inseridos no banco de dados do Spanner.

Para isso, clique no menu de navegação e acesse "Spanner". Nessa página, navegue até sample-instance e sample-database. Em seguida, clique em Query.

Queremos selecionar o número de game_items:

SELECT COUNT(*) FROM game_items;

Na parte de baixo, você vai encontrar o resultado.

137ce291a2ff2706.png

Não precisamos de muitas game_items. Mas agora eles estão disponíveis para os jogadores adquirirem!

Executar o perfil de carga de trabalho

Com seu game_items inicializado, a próxima etapa é fazer com que os jogadores se inscrevam para jogar.

O profile-workload vai usar o Locust para simular jogadores criando contas, fazendo login, recuperando informações de perfil e fazendo logout. Todos eles testam os endpoints do serviço de back-end profile em uma carga de trabalho típica semelhante à de produção.

Para executar isso, receba o IP externo do profile-workload:

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

Resposta ao comando

{PROFILEWORKLOAD_EXTERNAL_IP}

Agora, abra uma nova guia do navegador e acesse http://{PROFILEWORKLOAD_EXTERNAL_IP}:8089. Você vai receber uma página do Locust semelhante à anterior.

Nesse caso, você vai usar http://profile para o host. e não especifique um ambiente de execução nas opções avançadas. Além disso, especifique users como 4, o que vai simular quatro solicitações de usuário por vez.

O teste profile-workload vai ficar assim:

f6e0f06efb0ad6e.png

Clique em "Iniciar swarming".

Assim como antes, as estatísticas dos vários endpoints REST profile vão começar a aparecer. Clique em "Gráficos" para ver uma visão geral do desempenho de tudo.

4c2146e1cb3de23e.png

Resumo

Nesta etapa, você gerou alguns game_items e consultou a tabela game_items usando a interface de consulta do Spanner no console do Cloud.

Você também permitiu que os jogadores se inscrevessem no jogo e viu como o Locust pode criar cargas de trabalho semelhantes à produção nos serviços de back-end.

Próximas etapas

Depois de executar as cargas de trabalho, verifique o comportamento do cluster do GKE e da instância do Spanner.

8. Analisar o uso do GKE e do Spanner

Com o serviço de perfil em execução, é hora de aproveitar a oportunidade para ver como o cluster do Autopilot do GKE e o Cloud Spanner estão se comportando.

Verificar o cluster do GKE

Navegue até o cluster do Kubernetes. Como você implantou as cargas de trabalho e os serviços, o cluster agora tem alguns detalhes adicionados sobre o total de vCPUs e memória. Essas informações não estavam disponíveis quando não havia cargas de trabalho no cluster.

61d2d766c1f10079.png

Agora, clique no cluster sample-game-gke e mude para a guia "Observabilidade":

fa9acc7e26ea04a.png

O namespace do Kubernetes default deve ter ultrapassado o namespace kube-system para utilização da CPU, já que nossas cargas de trabalho e serviços de back-end são executados em default. Se não, verifique se o profile workload ainda está em execução e aguarde alguns minutos para que os gráficos sejam atualizados.

Para saber quais cargas de trabalho estão consumindo mais recursos, acesse o painel Workloads.

Em vez de acessar cada carga de trabalho individualmente, vá direto para a guia "Observabilidade" do painel. Você vai notar que o uso de CPU de profile e profile-workload aumentou.

f194b618969cfa9e.png

Agora, verifique o Cloud Spanner.

Verificar a instância do Cloud Spanner

Para verificar a performance do Cloud Spanner, acesse o Spanner e clique na instância sample-instance e no banco de dados sample-game.

Lá, você vai encontrar uma guia Insights do sistema no menu à esquerda:

216212182a57dfd1.png

Há muitos gráficos aqui para ajudar você a entender o desempenho geral da sua instância do Spanner, incluindo CPU utilization, transaction latency and locking e query throughput.

Além do System Insights, você pode acessar informações mais detalhadas sobre a carga de trabalho de consultas nos outros links da seção "Observabilidade":

  • Os insights de consulta ajudam a identificar as principais consultas que utilizam recursos no Spanner.
  • Os insights de transação e bloqueio ajudam a identificar transações com altas latências.
  • O Key Visualizer ajuda a visualizar padrões de acesso e pode ajudar a rastrear pontos de acesso nos dados.

Resumo

Nesta etapa, você aprendeu a verificar algumas métricas básicas de desempenho do Autopilot do GKE e do Spanner.

Por exemplo, com a carga de trabalho do seu perfil em execução, consulte a tabela players para ter mais informações sobre os dados armazenados nela.

Próximas etapas

Em seguida, é hora de limpar!

9. Limpar

Antes de fazer a limpeza, confira as outras cargas de trabalho que não foram abordadas. Especificamente matchmaking-workload, game-workload e tradepost-workload.

Quando terminar de "jogar", você pode limpar o playground. Felizmente, isso é bem fácil.

Primeiro, se o profile-workload ainda estiver em execução no navegador, pare-o:

13ae755a11f3228.png

Faça o mesmo para cada carga de trabalho que você testou.

Em seguida, no Cloud Shell, navegue até a pasta "infrastructure". Você vai destroy a infraestrutura usando o Terraform:

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

Resposta ao 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.

No console do Cloud, navegue até Spanner, Kubernetes Cluster, Artifact Registry, Cloud Deploy e IAM para validar se todos os recursos foram removidos.

10. Parabéns!

Parabéns! Você implantou aplicativos de amostra em Go no Autopilot do GKE e os conectou ao Cloud Spanner usando a Identidade da carga de trabalho.

Além disso, essa infraestrutura foi facilmente configurada e removida de maneira repetível usando o Terraform.

Leia mais sobre os serviços do Google Cloud com que você interagiu neste codelab:

A seguir

Agora que você tem um entendimento básico de como o Autopilot do GKE e o Cloud Spanner podem trabalhar juntos, que tal dar o próximo passo e começar a criar seu próprio aplicativo para trabalhar com esses serviços?