使用 GKE Autopilot 和 Spanner 部署应用

本教程介绍如何将容器化 Web 应用部署到 Google Kubernetes Engine (GKE) Autopilot 集群,并在后端使用 Google Spanner 数据库来存储数据。示例应用用来管理一个游戏玩家表。您可以通过应用的图形界面 (GUI) 添加和删除玩家。

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

在阅读本页面内容之前,请确保您熟悉 Kubernetes

为何选择 GKE 和 Spanner

作为开发者,您可能不希望花时间来确定应用所需的存储空间和计算资源数量,也不想在需求波动期间预测 RAM 和 CPU 使用率,亦不愿成天担心应用在遇到峰值负载时发生故障。

通过将 GKE Autopilot 作为一项全代管式 Kubernetes 服务来使用,将 Spanner 作为一项全代管式数据库服务来使用,您可以在稳定的基础架构上更快地开发和部署应用,简化资源配置和管理过程。GKE Autopilot 会根据运行时的要求在集群中添加或移除节点,以合理配置和扩缩用于托管应用的基础架构。同样,在存储空间或计算要求发生变化时,Spanner 亦能够以最小的人工干预进行动态扩缩。

例如,假设您将发布下一款重磅游戏,并且预计该游戏会迅速成为热门游戏,因此在发布周便会吸引大量网络流量。Spanner 通过即时增加、减少或重新分配计算资源,帮助您应对激增的吞吐量,同时还可利用 GKE Autopilot 最大限度地提高应用可用性。

配置 Spanner

如需配置 Spanner,您需要创建一个 Spanner 实例和一个 Spanner 数据库。

创建 Spanner 实例

Spanner 实例可用于分配在其中创建的 Spanner 数据库所使用的资源。

创建一个名为 hello-instance 的 Spanner 实例,并为该实例设置单区域配置和 100 处理单元的计算容量。

gcloud spanner instances create hello-instance \
    --config=regional-COMPUTE_REGION \
    --description="Spanner sample instance" \
    --processing-units=100

在本教程中,将 COMPUTE_REGION 替换为 us-west1

创建 Spanner 数据库

Spanner 数据库包含表、视图和索引。数据库会从其父实例继承属性,例如其配置(单区域或多区域)、可用计算容量和存储空间。

使用 GoogleSQL 方言,创建一个名为 hello-database 的 Spanner 数据库,其中包含名为 Players 的表。在 Cloud Shell 中运行以下查询:

gcloud spanner databases create hello-database \
    --instance=hello-instance \
    --database-dialect=GOOGLE_STANDARD_SQL \
    --ddl="CREATE TABLE Players (
        PlayerUuid STRING(36) NOT NULL,
        FirstName STRING(1024),
        LastName STRING(1024),
        BirthDate DATE) PRIMARY KEY(PlayerUuid)"

创建 GKE Autopilot 集群

配置 Spanner 后,创建一个 Autopilot 集群并使用适用于 GKE 的工作负载身份联合以安全且易于管理的方式访问您的数据库。

创建一个名为 hello-cluster 的 Autopilot 集群。默认情况下,Autopilot 集群会启用适用于 GKE 的工作负载身份联合。

gcloud container clusters create-auto CLUSTER_NAME \
  --location=CONTROL_PLANE_LOCATION

替换以下内容:

  • CLUSTER_NAMEhello-cluster
  • CONTROL_PLANE_LOCATION:集群控制平面的 Compute Engine 区域。在本教程中,请使用您在其中创建 Spanner 实例的区域,即 us-west1。建议您在同一区域中创建 Spanner 实例和 GKE Autopilot 集群,以减少延迟时间。

创建集群最多可能需要 8-10 分钟。

输出类似于以下内容:

NAME: hello-cluster
LOCATION: us-west1
MASTER_VERSION: 1.26.5-gke.1200
MASTER_IP: 192.0.2.1
MACHINE_TYPE: e2-medium
NODE_VERSION: 1.26.5-gke.1200
NUM_NODES: 3
STATUS: RUNNING

配置集群以使用适用于 GKE 的工作负载身份联合

在部署应用之前,配置您的集群以使用 Workload Identity Federation for GKE 向 Google Cloud 进行身份验证。

  1. 获取凭据以访问集群:

    gcloud container clusters get-credentials CLUSTER_NAME \
      --location=CONTROL_PLANE_LOCATION
    

    请替换以下内容:

    • CLUSTER_NAMEhello-cluster
    • CONTROL_PLANE_LOCATIONus-west1

    这会使用相应的凭据和端点信息更新 kubeconfig 文件,以将 kubectl 指向您的集群。

  2. 创建用于 Kubernetes 服务账号的命名空间。您还可以使用默认命名空间或任何现有命名空间。

    kubectl create namespace NAMESPACE
    

    NAMESPACE 替换为您要创建的新命名空间的名称,即 hello-namespace

  3. 为您的应用创建 Kubernetes 服务账号:

    kubectl create serviceaccount KSA_NAME \
      --namespace NAMESPACE
    

    请替换以下内容:

    • KSA_NAMEksa-helloapp,即您要创建的新 Kubernetes 服务账号的名称。
    • NAMESPACEhello-namespace
  4. 为您的应用创建 IAM 服务账号:

    gcloud iam service-accounts create GSA_NAME \
      --project=GSA_PROJECT
    

    请替换以下内容:

    • GSA_NAMEgsa-helloapp,即您要创建的新 IAM 服务账号的名称。
    • GSA_PROJECT:您的 Google Cloud项目 ID。在本教程中,您将在要部署示例应用的 Google Cloud 项目中创建 IAM 服务账号。因此,您的 GSA_PROJECT 和Google Cloud PROJECT_ID 是相同的。
  5. 为您的 IAM 服务账号添加 IAM 政策绑定,以便对 Spanner 执行读写操作:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member "serviceAccount:GSA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
      --role "roles/spanner.admin"
    

    替换以下内容:

    • PROJECT_ID:您的 Google Cloud 项目 ID
    • GSA_NAMEgsa-helloapp

    示例:

    gcloud projects add-iam-policy-binding my-gcp-project \
      --member "serviceAccount:gsa-helloapp@my-gcp-project.iam.gserviceaccount.com" \
      --role "roles/spanner.admin"
  6. 通过在两个服务账号之间添加 IAM 政策绑定,允许 Kubernetes 服务账号模拟 IAM 服务账号。此绑定允许 Kubernertes 服务账号充当 IAM 服务账号,以便 Kubernetes 服务账号可以对 Spanner 执行读写操作。

    gcloud iam service-accounts add-iam-policy-binding GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"
    

    请替换以下内容:

    • GSA_NAMEgsa-helloapp
    • GSA_PROJECT:您的 Google Cloud 项目 ID
    • PROJECT_ID:您的 Google Cloud 项目 ID
    • NAMESPACEhello-namespace
    • KSA_NAMEksa-helloapp

    示例:

    gcloud iam service-accounts add-iam-policy-binding gsa-helloapp@my-gcp-project.iam.gserviceaccount.com \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:my-gcp-project.svc.id.goog[hello-namespace/ksa-helloapp]"
  7. 使用 IAM 服务账号的电子邮件地址为 Kubernetes 服务账号添加注解。这样,您的示例应用便知道要用于访问 Google Cloud 服务的服务账号。因此,在应用要使用任何标准 Google API 客户端库访问 Google Cloud 服务时,便会使用该 IAM 服务账号。

    kubectl annotate serviceaccount KSA_NAME \
      --namespace NAMESPACE \
      iam.gke.io/gcp-service-account=GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com
    

    替换以下内容:

    • KSA_NAMEksa-helloapp
    • NAMESPACEhello-namespace
    • GSA_NAMEgsa-helloapp
    • GSA_PROJECT:您的 Google Cloud 项目 ID

    示例:

    kubectl annotate serviceaccount ksa-helloapp \
      --namespace hello-namespace \
      iam.gke.io/gcp-service-account=gsa-helloapp@my-gcp-project.iam.gserviceaccount.com

将示例应用部署到集群

现在,您已为 GKE 和 Spanner 设置了必要的服务和身份验证,接下来便可以部署示例应用 hello-app-cloud-spanner

  1. 将示例应用从 GitHub 代码库克隆到 Cloud Shell:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
    
  2. 通过点击终端窗口工具栏上的 代码编辑器按钮 打开编辑器,启动 Cloud Shell Editor。

    如需了解详情,请参阅 Cloud Shell Editor 界面概览

  3. 打开 Cloud Shell Editor 的探索器窗格,然后浏览到 kubernetes-engine-samples/databases/hello-app-cloud-spanner/k8s 目录。

  4. 打开 deployment.yaml 文件,将 <KSA_NAME> 替换为 Kubernetes 服务账号的名称 ksa-helloapp,以更新 serviceAccountName 字段。

    修改 yaml 以更新 KSA_NAME。
    图 1:在部署文件中更新 Kubernetes 服务账号名称。
  5. 关闭 Cloud Shell Editor,然后返回到 Cloud Shell 终端。

  6. 在 Cloud Shell 终端中,导航到 hello-app-cloud-spanner 目录:

    cd kubernetes-engine-samples/databases/hello-app-cloud-spanner
    
  7. 部署应用:

    kubectl apply -f k8s/deployment.yaml -n=NAMESPACE
    

    NAMESPACE 替换为 hello-namespace

  8. 等待应用部署完毕,即 STATUS 显示为 Running

    kubectl get pods -n=NAMESPACE --watch
    

    NAMESPACE 替换为 hello-namespace

    输出类似于以下内容:

    NAME                                       READY   STATUS              RESTARTS   AGE
    hello-app-cloud-spanner-765c9b8779-lfcrc   0/1     ContainerCreating   0          87s
    hello-app-cloud-spanner-765c9b8779-lfcrc   1/1     Running             0          3m15s
    
  9. 按键盘上的 Ctrl+C 返回命令提示符,以便运行更多命令。

将示例应用公开发布到互联网

如需在集群外部公开 Kubernetes Service,请创建 LoadBalancer 类型的 Service。此类型的 Service 会为可通过互联网访问的 Pod 生成外部负载均衡器 IP 地址。

  1. 部署负载均衡器:

    kubectl apply -f k8s/service.yaml -n=NAMESPACE
    

    NAMESPACE 替换为 hello-namespace

  2. 监视要分配的外部 IP 地址:

    kubectl get service -n=NAMESPACE --watch
    

    NAMESPACE 替换为 hello-namespace

  3. 分配完成后,复制 EXTERNAL-IP(例如 203.0.113.0)并在浏览器中将其打开。此时会打开一个网页界面,可在该界面显示和管理玩家数据库。

  4. 您可以使用应用 GUI 创建或删除玩家记录,这些记录保存在 Spanner 数据库中。

    添加或删除玩家。
    图 2. 在注册表中创建或删除玩家。

    运行以下查询以验证 Spanner 数据库是否已用您的条目进行更新:

    gcloud spanner databases execute-sql hello-database \
      --instance=hello-instance \
      --sql="SELECT * FROM Players LIMIT 10"
    

    输出类似于以下内容:

    PlayerUuid: a1f34bbf-929c-498d-8b16-39bbb29d70e3
    FirstName: John
    LastName: Smith
    BirthDate: 1997-07-12
    
    PlayerUuid: d634e157-96ea-45f2-be3f-fb907ced188e
    FirstName: Jane
    LastName: Doe
    BirthDate: 2013-07-12