连接 Cloud Spanner 和 GKE Autopilot

1. 简介

Cloud Spanner 是一项可横向扩容的全球分布式全代管式关系型数据库服务,可提供 ACID 事务和 SQL 语义,同时不会影响性能和高可用性。

GKE Autopilot 是 GKE 中的一种操作模式,在该模式下,Google 会管理您的集群配置,包括节点、扩缩、安全性和其他预配置设置,以遵循最佳实践。例如,GKE Autopilot 支持 Workload Identity 来管理服务权限。

本实验的目标是引导您完成将 GKE Autopilot 上运行的多个后端服务连接到 Cloud Spanner 数据库的过程。

3d810aa9ec80a271

在本实验中,您将首先设置一个项目并启动 Cloud Shell。然后,您将使用 Terraform 部署基础设施。

完成后,您将与 Cloud Build 和 Cloud Deploy 交互,为游戏数据库执行初始架构迁移、部署后端服务,然后部署工作负载。

此 Codelab 中的服务与 Cloud Spanner 游戏开发入门 Codelab 中的服务相同。若要使服务在 GKE 上运行并连接到 Spanner,无需完成该 Codelab。不过,如果您想详细了解在 Spanner 上运行的那些服务的具体细节,不妨了解一下。

在工作负载和后端服务运行的情况下,您可以开始产生负载,并观察服务如何协同工作。

最后,您将清理在本实验中创建的资源。

构建内容

在本实验中,您将:

  • 使用 Terraform 预配基础设施
  • 在 Cloud Build 中使用架构迁移过程创建数据库架构
  • 部署四个 Golang 后端服务,这些服务利用 Workload Identity 连接到 Cloud Spanner
  • 部署四个用于模拟后端服务负载的工作负载服务。

学习内容

  • 如何使用 Terraform 预配 GKE Autopilot、Cloud Spanner 和 Cloud Deploy 流水线
  • Workload Identity 如何让 GKE 上的服务能够模拟服务账号以访问 IAM 权限以使用 Cloud Spanner
  • 如何使用 Locust.io 在 GKE 和 Cloud Spanner 上生成类似生产的负载

所需条件

  • 与结算账号关联的 Google Cloud 项目。
  • 网络浏览器,例如 ChromeFirefox

2. 设置和要求

创建项目

如果您还没有 Google 账号(Gmail 或 Google Apps),则必须创建一个。登录 Google Cloud Platform 控制台 ( console.cloud.google.com) 并创建一个新项目。

如果您已经有一个项目,请点击控制台左上方的项目选择下拉菜单:

6c9406d9b014760.png

然后点击新建项目按钮以创建新项目:

949d83c8a4ee17d9

如果您还没有项目,则应该看到一个类似这样的对话框来创建您的第一个项目:

870a3cbd6541ee86.png

随后的项目创建对话框可让您输入新项目的详细信息:

6a92c57d3250a4b3.png

请记住项目 ID,它是所有 Google Cloud 项目中的唯一名称(很抱歉,上述名称已被占用,您无法使用!)。它稍后将在此 Codelab 中被称为 PROJECT_ID

接下来,如果尚未执行此操作,则需要在 Developers Console 中启用结算功能,以便使用 Google Cloud 资源并启用 Cloud Spanner API

15d0ef27a8fbab27.png

在此 Codelab 中运行仅花费几美元,但是如果您决定使用更多资源或继续让它们运行,费用可能更高(请参阅本文档末尾的“清理”部分)。如需了解 Google Cloud Spanner 价格,请点击此处;如需了解 GKE Autopilot,请点击此处

Google Cloud Platform 的新用户均有资格获享 $300 赠金,免费试用此 Codelab。

Cloud Shell 设置

虽然 Google Cloud 和 Spanner 可以从笔记本电脑远程操作,但在此 Codelab 中,我们将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。

基于 Debian 的这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证。这意味着在本 Codelab 中,您只需要一个浏览器(没错,它适用于 Chromebook)。

  1. 如需从 Cloud 控制台激活 Cloud Shell,只需点击“激活 Cloud Shell”图标 gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A 即可(预配和连接到环境应该只需要片刻时间)。

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

Screen Shot 2017-06-14 at 10.13.43 PM.png

在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设置为您的 PROJECT_ID

gcloud auth list

命令输出

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

命令输出

[core]
project = <PROJECT_ID>

如果出于某种原因未设置项目,只需发出以下命令即可:

gcloud config set project <PROJECT_ID>

正在查找您的 PROJECT_ID?检查您在设置步骤中使用的 ID,或在 Cloud Console 信息中心查找该 ID:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

默认情况下,Cloud Shell 还会设置一些环境变量,这对您日后运行命令可能会很有用。

echo $GOOGLE_CLOUD_PROJECT

命令输出

<PROJECT_ID>

下载代码

在 Cloud Shell 中,您可以下载本实验的代码:

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

命令输出

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

此 Codelab 基于 v0.1.3 版本,因此请查看该标记:

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

命令输出

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

现在,将当前工作目录设置为 DEMO_HOME 环境变量。这有助于您在学习此 Codelab 的不同部分时更轻松地进行导航。

export DEMO_HOME=$(pwd)

摘要

在此步骤中,您设置了新项目、激活了 Cloud Shell 并下载了本实验的代码。

后续步骤

接下来,您将使用 Terraform 预配基础设施。

3. 预配基础设施

概览

项目就绪后,就该开始运行基础架构了。这包括 VPC 网络、Cloud Spanner、GKE Autopilot、Artifact Registry(用于存储将在 GKE 上运行的映像)、用于后端服务和工作负载的 Cloud Deploy 流水线,以及能够使用这些服务的服务账号和 IAM 权限。

实在是很多。幸运的是,Terraform 可以简化这项设置工作。Terraform 是一种“基础设施即代码”工具,我们可以在一系列“.tf”中指定本项目所需的文件。这使得预配基础架构变得简单。

您不一定非要熟悉 Terraform 才能完成此 Codelab。不过,如果您想了解接下来的步骤,可以看看在 infrastructure 目录下的以下文件中创建的所有内容:

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

配置 Terraform

在 Cloud Shell 中,您将切换到 infrastructure 目录并初始化 Terraform:

cd $DEMO_HOME/infrastructure
terraform init

命令输出

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.

接下来,通过复制 terraform.tfvars.sample 并修改项目值来配置 Terraform。其他变量也可以更改,但只有项目需要更改,才能适应您的环境。

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

预配基础设施

现在,可以预配基础设施了!

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

命令输出

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.

查看已创建的内容

如需验证创建的内容,您需要在 Cloud 控制台中查看产品。

Cloud Spanner

首先,导航到汉堡式菜单并点击 Spanner,查看 Cloud Spanner。您可能需要点击“查看更多商品”可在列表中找到它。

系统随即会显示 Spanner 实例列表。点击实例,您将看到数据库。代码应如下所示:

10b7fc0c4a86c59

GKE Autopilot

接下来,前往汉堡式菜单并点击 Kubernetes Engine => Clusters,查看 GKE。在这里,您将看到 sample-games-gke 集群正在 Autopilot 模式下运行。

9cecb1a702e6b7ff.png

Artifact Registry

现在,您需要了解图片的存储位置。因此,点击汉堡式菜单并找到 Artifact Registry=>Repositories。Artifact Registry 位于菜单的 CI/CD 部分。

在这里,您将看到一个名为 spanner-game-images 的 Docker 注册表。目前,此字段为空。

3f805eee312841b

Cloud Deploy

Cloud Deploy 是创建流水线的位置,以便 Cloud Build 能够提供构建映像并将其部署到 GKE 集群的步骤。

转到汉堡式菜单,然后找到 Cloud Deploy,它也位于菜单的 CI/CD 部分中。

在这里,您会注意到两个流水线:一个用于后端服务,另一个用于工作负载。他们都将映像部署到同一 GKE 集群,但这可以实现部署分离。

d2e4a659145ddf5e.png

IAM

最后,查看 Cloud 控制台中的 IAM 页面,验证已创建的服务账号。导航到汉堡式菜单并找到 IAM and Admin=>Service accounts。代码应如下所示:

bed3d1af94974916.png

Terraform 总共创建了六个服务账号:

  • 默认的计算机服务账号。此 Codelab 中没有用到它。
  • cloudbuild-cicd 账号用于 Cloud Build 和 Cloud Deploy 步骤。
  • 四个“应用”用于与 Cloud Spanner 进行交互的后端服务。

接下来,您需要配置 kubectl 以与 GKE 集群进行交互。

配置 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

命令输出

#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

摘要

太棒了!您能够在专用网络的 VPC 中预配一个 Cloud Spanner 实例,即 GKE Autopilot 集群。

此外,还为后端服务和工作负载创建了两个 Cloud Deploy 流水线,以及一个用于存储构建的映像的 Artifact Registry 代码库。

最后,创建服务账号并将其配置为与 Workload Identity 搭配使用,以便后端服务使用 Cloud Spanner。

在部署后端服务和工作负载后,您还将 kubectl 配置为在 Cloud Shell 中与 GKE 集群交互。

后续步骤

您必须先定义数据库架构,然后才能使用这些服务。您将在下一步中进行设置。

4. 创建数据库架构

概览

在运行后端服务之前,您需要确保数据库架构已就位。

如果查看演示代码库中 $DEMO_HOME/schema/migrations 目录中的文件,您会看到一系列定义架构的 .sql 文件。这模拟了开发周期,在存储库中跟踪架构更改,并且可能与应用的某些功能相关联。

对于此示例环境,扳手是一个使用 Cloud Build 应用架构迁移的工具。

Cloud Build

$DEMO_HOME/schema/cloudbuild.yaml 文件描述了要执行的步骤:

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

基本上有两个步骤:

  • 将扳手下载到 Cloud Build 工作区
  • 运行扳手迁移

扳手需要具有 Spanner 项目、实例和数据库环境变量,才能连接到写入端点。

Cloud Build 能够进行这些更改,因为它是以 cloudbuild-cicd@${PROJECT_ID}.iam.gserviceaccount.com 服务账号的身份运行:

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

此服务账号具有 Terraform 添加的 spanner.databaseUser 角色,该角色允许服务账号更新 DDL。

架构迁移

系统会根据 $DEMO_HOME/schema/migrations 目录中的文件执行五个迁移步骤。下面是一个会创建 players 表和索引的 000001.sql 文件示例:

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

提交架构迁移

如需提交 build 以执行架构迁移,请切换到 schema 目录并运行以下 gcloud 命令:

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

命令输出

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

在上面的输出中,您会看到一个指向 Created Cloud Build 流程的链接。如果您点击该按钮,则会前往 Cloud 控制台中的构建页面,以便您监控构建进度并查看构建活动。

11b1cf107876d797

摘要

在此步骤中,您使用 Cloud Build 提交了应用了 5 个不同 DDL 操作的初始架构迁移。这些操作表示何时添加了需要更改数据库架构的特征。

在正常的开发场景中,您需要进行架构更改以向后兼容当前应用,以避免服务中断。

对于不向后兼容的更改,您需要分阶段将更改部署到应用和架构,以确保不会出现服务中断。

后续步骤

架构就绪后,下一步是部署后端服务!

5. 部署后端服务

概览

此 Codelab 的后端服务是代表四种不同服务的 golang REST API:

  • 玩家资料:为玩家提供注册和身份验证的功能,以便加入我们的示例“游戏”。
  • 配对:与玩家数据互动以帮助实现配对功能、跟踪所创建的游戏的相关信息,并在游戏结束时更新玩家统计数据。
  • 道具:让玩家在游戏过程中获得游戏道具和金钱。
  • Tradepost::让玩家能够在商品摊位上买卖物品

d36e958411d44b5d.png

如需详细了解这些服务,请参阅 Cloud Spanner 游戏开发入门 Codelab。出于我们的目的,我们希望这些服务在我们的 GKE Autopilot 集群上运行。

这些服务必须能够修改 Spanner 数据。为此,每个服务都会创建一个服务账号,向其授予“databaseUser”角色。

Workload Identity 允许 Kubernetes 服务账号模拟服务的Google Cloud 服务账号:

  • 创建服务的 Google Cloud 服务账号 (GSA) 资源
  • databaseUser 角色分配给该服务账号
  • workloadIdentityUser 角色分配给该服务账号
  • 创建引用 GSA 的 Kubernetes 服务账号 (KSA)

粗略的图表如下所示:

a8662d31d66b5910.png

Terraform 为您创建了服务账号和 Kubernetes 服务账号。您可以使用 kubectl 检查 Kubernetes 服务账号:

# 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

构建的运作方式如下:

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
  • Cloud Build 命令会读取此文件并按照列出的步骤执行操作。首先,它构建服务映像。然后,它会执行 gcloud deploy create 命令。这将读取 $DEMO_HOME/backend_services/skaffold.yaml 文件,该文件定义每个部署文件的位置:
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 将遵循每项服务的 deployment.yaml 文件的定义。服务的部署文件包含用于创建服务的信息,在本例中,该服务是在端口 80 上运行的 clusterIP。

"ClusterIP" 类型可防止后端服务 Pod 具有外部 IP,因此只有可连接到内部 GKE 网络的实体才能访问后端服务。玩家应该不能直接访问这些服务,因为他们可以访问和修改 Spanner 数据。

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

除了创建 Kubernetes 服务之外,Cloud Deploy 还会创建 Kubernetes 部署。我们来看看 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"

上半部分提供有关该服务的一些元数据。其中最重要的环节是定义此部署将创建的副本数量。

replicas: 2 # EDIT: Number of instances of deployment

接下来,我们会看到应该由哪个服务账号运行应用以及应使用哪个映像。这些 ID 会与通过 Terraform 创建的 Kubernetes 服务账号以及在 Cloud Build 步骤中创建的映像相匹配。

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

然后,我们指定一些有关网络和环境变量的信息。

spanner_config 是一个 Kubernetes ConfigMap,用于指定应用连接到 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_HOSTSERVICE_PORT 是服务用来知道绑定位置的其他环境变量。

最后一部分告知 GKE 可以为此部署中的每个副本允许多少资源。这也是 GKE Autopilot 根据需要扩缩集群的工具。

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

有了这些信息,您就可以部署后端服务了。

部署后端服务

如前所述,部署后端服务需要使用 Cloud Build。与架构迁移一样,您可以使用 gcloud 命令行提交构建请求:

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

命令输出

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

schema migration 步骤的输出不同,此构建的输出指示创建了一些映像。这些文件将存储在您的 Artifact Registry 代码库中。

gcloud build 步骤的输出将包含指向 Cloud 控制台的链接。看看这些。

收到来自 Cloud Build 的成功通知后,导航到 Cloud Deploy,然后转到 sample-game-services 流水线,以监控部署的进度。

df5c6124b9693986.png

部署服务后,您可以查看 kubectl 以查看 Pod 的状态:

kubectl get pods

命令输出

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

然后,检查服务以查看 ClusterIP 的实际运用:

kubectl get services

命令输出

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

您还可以前往 Cloud 控制台中的 GKE 界面,查看 WorkloadsServicesConfigMaps

工作负载

da98979ae49e5a30.png

服务

406ca2fe7ad4818b

ConfigMap

a0ebd34ee735ee11.png

3b9ef91c77a4e7f0

摘要

在此步骤中,您已将四个后端服务部署到 GKE Autopilot。您可以在 Cloud Console 中运行 Cloud Build 步骤并检查 Cloud Deploy 和 Kubernetes 上的进度。

您还了解了这些服务如何利用 Workload Identity 来模拟对 Spanner 数据库拥有适当权限的服务账号。

后续步骤

在下一部分中,您将部署工作负载。

6. 部署工作负载

概览

现在后端服务正在集群上运行,接下来您将部署工作负载。

dd900485e2eeb611.png

这些工作负载可从外部访问,对于此 Codelab,每个后端服务都有一个对应的工作负载。

这些工作负载是基于 Locust 的负载生成脚本,模拟这些示例服务预期的真实访问模式。

Cloud Build 流程包含以下文件:

  • $DEMO_HOME/workloads/cloudbuild.yaml(由 Terraform 生成)
  • $DEMO_HOME/workloads/skaffold.yaml
  • 每个工作负载的 deployment.yaml 文件

工作负载 deployment.yaml 文件看起来与后端服务部署文件略有不同。

以下是 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"

该文件的顶部定义了服务。在这种情况下,系统会创建一个 LoadBalancer,并在端口 8089 上运行工作负载。

LoadBalancer 将提供一个可用于连接到工作负载的外部 IP。

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

部署部分的顶部是工作负载的元数据。在这种情况下,只部署一个副本:

replicas: 1 

但容器规范有所不同。首先,我们使用的是 default Kubernetes 服务账号。此账号没有任何特殊权限,因为工作负载不需要连接到除 GKE 集群上运行的后端服务之外的任何 Google Cloud 资源。

另一个区别是,这些工作负载不需要任何环境变量。从而缩短了部署规范。

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

资源设置与后端服务类似。请记住,GKE Autopilot 正是通过这种方式才能知道需要多少资源来满足集群上运行的所有 Pod 的请求。

开始部署工作负载吧!

部署工作负载

和之前一样,您可以使用 gcloud 命令行提交构建请求:

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

命令输出

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

请务必在 Cloud 控制台中查看 Cloud Build 日志和 Cloud Deploy 流水线,以检查状态。对于工作负载,Cloud Deploy 流水线为 sample-game-workloads

部署完成后,在 Cloud Shell 中使用 kubectl 检查状态:

kubectl get pods

命令输出

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

然后,检查工作负载服务以查看 LoadBalancer 的实际运用:

kubectl get services 

命令输出

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

摘要

现在,您已将工作负载部署到 GKE 集群。这些工作负载不需要额外的 IAM 权限,并且可以在端口 8089 上使用 LoadBalancer 服务从外部访问。

后续步骤

后端服务和工作负载都在运行,接下来就可以开始“发挥”比赛!

7. 开始玩游戏

概览

示例“游戏”的后端服务您还可以通过多种方式与这些服务进行交互的操作。

每个工作负载都使用 Locust 来模拟针对我们服务 API 的实际负载。在此步骤中,您将运行多个工作负载,以在 GKE 集群和 Spanner 上生成负载,并在 Spanner 上存储数据。

以下是对每个工作负载的说明:

  • item-generator 工作负载是用于生成 game_items 列表的快速工作负载,玩家可以在“玩游戏”过程中获取该列表游戏。
  • profile-workload 可模拟玩家注册和登录。
  • matchmaking-workload 可模拟排队等待分配给游戏的玩家。
  • game-workload 可模拟玩家在游戏过程中获取 game_items 和金钱。
  • tradepost-workload 可模拟玩家能够在交易站买卖商品。

此 Codelab 将重点介绍如何运行 item-generatorprofile-workload

运行商品生成器

item-generator 使用 item 后端服务端点将 game_items 添加到 Spanner。这些项是 game-workloadtradepost-workload 正常运行所必需的。

第一步是获取 item-generator 服务的外部 IP。在 Cloud Shell 中,运行以下命令:

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

命令输出

{ITEMGENERATOR_EXTERNAL_IP}

现在,打开新的浏览器标签页,并将其指向 http://{ITEMGENERATOR_EXTERNAL_IP}:8089您应该会看到如下页面:

817307157d66c661

您应将 usersspawn 保留为默认值 1。对于 host,请输入 http://item。点击高级选项,然后输入 10s 作为运行时间。

配置应如下所示:

f3143165c6285c21.png

点击“Start swarming”!

对于在 POST /items 端点上发出的请求,统计信息将开始显示。10 秒后,系统将停止加载。

点击Charts,您会看到一些有关这些请求效果的图表。

abad0a9f3c165345.png

现在,您想要检查数据是否已输入 Spanner 数据库。

为此,请点击汉堡式菜单并导航到“Spanner”。在此页面中,导航到 sample-instancesample-database。然后点击“Query”。

我们想要选择 game_items 的数量:

SELECT COUNT(*) FROM game_items;

您将在底部看到计算结果。

137ce291a2ff2706

我们不需要很多 game_items 种子。不过现在玩家可以获取它们了!

运行 profile-workload

添加game_items种子后,下一步就是让玩家注册以便玩游戏。

profile-workload 将使用 Locust 模拟玩家创建账号、登录、检索个人资料信息和退出。所有这些都在类似生产的典型工作负载中测试 profile 后端服务的端点。

如需运行此命令,请获取 profile-workload 外部 IP:

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

命令输出

{PROFILEWORKLOAD_EXTERNAL_IP}

现在,打开新的浏览器标签页,并将其指向 http://{PROFILEWORKLOAD_EXTERNAL_IP}:8089您应该会看到与上一个类似的 Locust 页面。

在这种情况下,您将使用 http://profile 作为主机。您无需在高级选项中指定运行时。此外,将 users 指定为 4,这样一次模拟 4 个用户请求。

profile-workload 测试应如下所示:

f6e0f06efb0ad6e.png

点击“Start swarming”!

和之前一样,各种 profile REST 端点的统计信息将开始显示。点击图表即可查看各方面的表现。

4c2146e1cb3de23e

摘要

在此步骤中,您生成了一些 game_items,然后使用 Cloud Console 中的 Spanner 查询界面查询了 game_items 表。

您还允许玩家注册您的游戏,并了解 Locust 如何针对您的后端服务创建类似生产的工作负载。

后续步骤

运行工作负载后,您需要检查 GKE 集群和 Spanner 实例的行为。

8. 查看 GKE 和 Spanner 使用情况

在配置文件服务运行的情况下,可以借此机会了解您的 GKE Autopilot 集群和 Cloud Spanner 的表现。

检查 GKE 集群

导航到 Kubernetes 集群。请注意,由于您部署了工作负载和服务,因此集群现在添加了一些有关 vCPU 和内存总量的详细信息。当集群中没有任何工作负载时,此信息不可用。

61d2d766c1f10079

现在,点击进入 sample-game-gke 集群并切换到“可观测性”标签页:

fa9acc7e26ea04a.png

由于我们的工作负载和后端服务是在 default 上运行的,因此 default kubernetes 命名空间的 CPU 利用率应超过 kube-system 命名空间。如果未显示,请确保 profile workload 仍在运行,然后等待几分钟让图表更新。

如需查看哪些工作负载占用的资源最多,请前往 Workloads 信息中心。

无需单独进入每个工作负载,而是直接进入信息中心的“可观测性”标签页。您应该会看到 profileprofile-workload CPU 已增加。

f194b618969cfa9e.png

现在,查看 Cloud Spanner。

检查 Cloud Spanner 实例

如需查看 Cloud Spanner 的性能,请导航到 Spanner,然后点击进入 sample-instance 实例和 sample-game 数据库。

然后,您会在左侧菜单中看到 System Insights(系统数据分析)标签页:

216212182a57dfd1.png

此处提供了许多图表来帮助您了解 Spanner 实例的整体性能,包括 CPU utilizationtransaction latency and lockingquery throughput

除了 System Insights 之外,您还可以通过查看“可观测性”部分的其他链接来获取有关查询工作负载的更多详细信息:

  • 查询数据分析有助于确定利用 Spanner 资源的前 N 个查询。
  • 事务和锁定数据分析有助于识别延迟较高的事务。
  • Key Visualizer 有助于直观呈现访问模式,并且有助于跟踪数据中的热点。

摘要

在此步骤中,您学习了如何查看 GKE Autopilot 和 Spanner 的一些基本性能指标。

例如,在配置文件工作负载运行时,查询 players 表,获取有关存储在其中的数据的更多信息。

后续步骤

接下来该清理了!

9. 正在清理

在清理之前,您可以随意了解未涵盖的其他工作负载。具体而言,matchmaking-workloadgame-workloadtradepost-workload

当您完成“播放”后您可以清理自己的游乐场幸运的是,这非常简单。

首先,如果 profile-workload 仍在浏览器中运行,请查看并停止它:

13ae755a11f3228

对您可能测试过的每个工作负载执行相同的操作。

然后,在 Cloud Shell 中,导航到基础设施文件夹。您将使用 Terraform 对基础架构执行 destroy 操作:

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

命令输出

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.

在 Cloud 控制台中,前往 SpannerKubernetes ClusterArtifact RegistryCloud DeployIAM,验证所有资源是否已移除。

10. 恭喜!

恭喜,您已成功在 GKE Autopilot 上部署示例 golang 应用,并使用 Workload Identity 将其连接到 Cloud Spanner!

除此之外,使用 Terraform 以可重复的方式轻松设置和移除此基础设施。

您可以详细了解您在此 Codelab 中互动过的 Google Cloud 服务:

后续操作

至此您已经对 GKE Autopilot 和 Cloud Spanner 如何协同工作有了基本了解,何不继续下一步,开始构建您自己的应用来与这些服务搭配使用呢?