使用入门:GKE 上使用 ESPv2 的 Endpoints

本教程将介绍如何利用 Google Kubernetes Engine (GKE) 上的 Extensible Service Proxy V2 (ESPv2) 部署简单的示例 gRPC 服务。本教程使用 Python 版本的 bookstore-grpc 示例。如需其他语言的 gRPC 示例,请参阅后续步骤部分。

本教程使用了示例代码和 ESPv2 的预构建容器映像,这些映像存储在 Container Registry 中。如果您不熟悉容器,请参阅以下内容了解详情:

如需大致了解 Cloud Endpoints,请参阅 Endpoints 简介Endpoints 架构

目标

学习本教程时,请使用以下概要任务列表。为确保请求成功发送到 API,您必须完成所有任务。

  1. 设置 Google Cloud 项目,然后下载所需的软件。请参阅准备工作
  2. 复制并配置 bookstore-grpc 示例中的文件。请参阅配置 Endpoints
  3. 部署 Endpoints 配置以创建 Endpoints 服务。请参阅部署 Endpoints 配置
  4. 创建后端,以提供 API 并部署 API。请参阅部署 API 后端
  5. 获取服务的外部 IP 地址。请参阅获取服务的外部 IP 地址
  6. 向 API 发送请求。请参阅向 API 发送请求
  7. 避免向您的 Google Cloud 帐号收取费用。请参阅清理

费用

本教程使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用量来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本教程后,您可以删除所创建的资源以避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 登录您的 Google Cloud 帐号。如果您是 Google Cloud 新手,请创建一个帐号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到“项目选择器”

  3. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

  4. 记下 Google Cloud 项目 ID,因为以后需要它。
  5. 安装并初始化 Cloud SDK
  6. 更新 Cloud SDK 并安装 Endpoints 组件:
    gcloud components update
  7. 确保 Cloud SDK (gcloud) 有权访问您在 Google Cloud 上的数据和服务:
    gcloud auth login
    浏览器会打开一个新的标签页,并提示您选择帐号。
  8. 将默认项目设置为您的项目 ID。
    gcloud config set project YOUR_PROJECT_ID

    YOUR_PROJECT_ID 替换为您的项目 ID。

    如果您有其他 Google Cloud 项目,并且想使用 gcloud 来管理这些项目,请参阅管理 Cloud SDK 配置

  9. 安装 kubectl
    gcloud components install kubectl
  10. 获取新用户凭据以用作应用的默认凭据。需要用户凭据才能授权 kubectl
    gcloud auth application-default login
    在浏览器打开的新标签页中选择帐号。
  11. 按照 gRPC Python 快速入门中的步骤安装 gRPC 和 gRPC 工具。

配置 Endpoints

bookstore-grpc 示例包含您在本地复制并进行配置所需的文件。

  1. 通过服务 .proto 文件创建一个独立的 protobuf 描述符文件:
    1. 保存示例代码库中 bookstore.proto 的副本。此文件用于定义 Bookstore 服务的 API。
    2. 创建以下目录:mkdir generated_pb2
    3. 使用 protoc Protocol Buffers 编译器创建描述符文件 api_descriptor.pb。在您保存了 bookstore.proto 的目录中运行以下命令:
      python -m grpc_tools.protoc \
          --include_imports \
          --include_source_info \
          --proto_path=. \
          --descriptor_set_out=api_descriptor.pb \
          --python_out=generated_pb2 \
          --grpc_python_out=generated_pb2 \
          bookstore.proto
      

      在前面的命令中,--proto_path 设置为当前工作目录。在 gRPC 编译环境中,如果对 .proto 输入文件使用其他目录,请更改 --proto_path,以便编译器搜索您保存了 bookstore.proto 文件的目录。

  2. 创建 gRPC API 配置 YAML 文件:
    1. 保存 api_config.yaml 文件的副本。此文件用于定义 Bookstore 服务的 gRPC API 配置
    2. api_config.yaml 文件中的 MY_PROJECT_ID 替换为您的 Google Cloud 项目 ID。例如:
      #
      # Name of the service configuration.
      #
      name: bookstore.endpoints.example-project-12345.cloud.goog
      

      请注意,此文件中 apis.name 字段的值应该与 .proto 文件中的完全限定 API 名称完全匹配;否则部署将无法正常运行。Bookstore 服务是在 endpoints.examples.bookstore 包内的 bookstore.proto 中定义的。其完全限定的 API 名称为 endpoints.examples.bookstore.Bookstore,与其在 api_config.yaml 文件中的名称相同。

      apis:
        - name: endpoints.examples.bookstore.Bookstore
      

如需了解详情,请参阅配置 Endpoints

部署 Endpoints 配置

如需部署 Endpoints 配置,请使用 gcloud endpoints services deploy 命令。此命令使用 Service Management 创建一项托管式服务。

  1. 确保您位于 api_descriptor.pbapi_config.yaml 文件所在的目录中。
  2. 确认 gcloud 命令行工具当前使用的默认项目是您要向其部署 Endpoints 配置的 Google Cloud 项目。验证从以下命令返回的项目 ID,以确保不会在错误的项目中创建服务。
    gcloud config list project
    

    如果您需要更改默认项目,请运行以下命令:

    gcloud config set project YOUR_PROJECT_ID
    
  3. 使用 gcloud 命令行工具部署 proto descriptor 文件和配置文件:
    gcloud endpoints services deploy api_descriptor.pb api_config.yaml
    

    在创建和配置服务时,Service Management 会向终端输出信息。部署完成后,系统将显示如下所示的消息:

    Service Configuration [CONFIG_ID] uploaded for service [bookstore.endpoints.example-project.cloud.goog]

    CONFIG_ID 是部署创建的唯一 Endpoints 服务配置 ID。例如:

    Service Configuration [2017-02-13r0] uploaded for service [bookstore.endpoints.example-project.cloud.goog]
    

    在前面的示例中,2017-02-13r0 是服务配置 ID,bookstore.endpoints.example-project.cloud.goog 是服务名称。服务配置 ID 由日期戳后跟一个修订版本号组成。如果您在同一天再次部署 Endpoints 配置,服务配置 ID 中的修订版本号将递增。

检查所需服务

Endpoints 和 ESP 至少需要启用以下 Google 服务:
姓名 标题
servicemanagement.googleapis.com Service Management API
servicecontrol.googleapis.com Service Control API
endpoints.googleapis.com Google Cloud Endpoints

在大多数情况下,gcloud endpoints services deploy 命令会启用这些必需的服务。但在以下情况下,gcloud 命令会成功完成,但不启用必需的服务:

  • 您使用了 Terraform 之类的第三方应用,但未添加这些服务。

  • 您将 Endpoints 配置部署到已明确停用这些服务的现有 Google Cloud 项目。

使用以下命令确认必需服务是否已启用:

gcloud services list

如果您没有看到列出的必需服务,请启用它们:

gcloud services enable servicemanagement.googleapis.com
gcloud services enable servicecontrol.googleapis.com
gcloud services enable endpoints.googleapis.com

同时启用 Endpoints 服务:

gcloud services enable ENDPOINTS_SERVICE_NAME

要确定 ENDPOINTS_SERVICE_NAME,您可以执行以下任一操作:

  • 部署 Endpoints 配置后,转到 Cloud Console 中的 Endpoints 页面。服务名称列下显示了可能的 ENDPOINTS_SERVICE_NAME 列表。

  • 对于 OpenAPI,ENDPOINTS_SERVICE_NAME 是您在 OpenAPI 规范的 host 字段中指定的值。对于 gRPC,ENDPOINTS_SERVICE_NAME 是您在 gRPC Endpoints 配置的 name 字段中指定的值。

如需详细了解 gcloud 命令,请参阅 gcloud 服务

如果您收到错误消息,请参阅排查 Endpoints 配置部署问题

如需了解更多信息,请参阅部署 Endpoints 配置

部署 API 后端

目前,您已将服务配置部署到 Service Management,但尚未部署将提供 API 后端的代码。本部分介绍了如何创建 GKE 集群以托管 API 后端,以及如何部署 API。

创建容器集群

集群需要 IP 别名才能使用容器原生负载平衡。为示例创建具有 IP 别名的容器集群:

gcloud container clusters create espv2-demo-cluster \
    --enable-ip-alias \
    --create-subnetwork="" \
    --network=default \
    --zone=us-central1-a

上面的命令会在可用区 us-central1-a 中创建一个具有自动预配子网的集群 espv2-demo-cluster

kubectl 向容器集群进行身份验证

要使用 kubectl 创建和管理集群资源,您需要获取集群凭据并将其提供给 kubectl。为此,请运行以下命令:将 NAME 替换为新的集群名称,将 ZONE 替换为其集群区域。

gcloud container clusters get-credentials NAME --zone ZONE

检查所需权限

请按照此权限建议选择合适的节点服务帐号,作为与 Google 服务通信的身份。ESP 和 ESPv2 需要与 Google ServiceController 和 Stackdriver 通信,运行 ESP 和 ESPv2 的节点服务帐号需要额外的 IAM 角色。

如果节点服务帐号不是 Compute Engine 默认服务帐号,请按照下一步添加所需的 IAM 角色:

添加所需的 IAM 角色:

用于 ESP 和 ESPv2 的服务帐号需要以下 IAM 角色。

如需将 Service Controller 和 Cloud Trace Agent IAM 角色添加到服务帐号,请执行以下操作:

控制台

  1. 在 Cloud Console 中,选择您在其中创建了服务帐号的项目。
  2. 打开 IAM/Iam 页面

    转到“IAM/Iam”页面

    。该页面应该列出所有 IAM 成员,包括所有服务帐号。
  3. 选择您的服务帐号,然后点击右侧的修改图钉。
  4. 此时将打开修改权限面板。
  5. 点击 + 添加其他角色
  6. 点击选择角色,然后选择 Service Management > Service Controller
  7. 点击 + 添加其他角色
  8. 点击选择角色,然后选择 Cloud Trace > Cloud Trace Agent
  9. 点击保存
  10. 现在,您可以在 IAM 页面上服务帐号的角色列中查看 Service ControllerCloud Trace Agent 角色。

gcloud

  1. 添加 Service Controller 角色:

    gcloud projects add-iam-policy-binding PROJECT_ID \
            --member serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
            --role roles/servicemanagement.serviceController
  2. 添加 Cloud Trace Agent 角色以启用 Cloud Trace:

    gcloud projects add-iam-policy-binding PROJECT_ID \
            --member serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
            --role roles/cloudtrace.agent

如需了解详情,请参阅什么是角色和权限?

Workload Identity:

如果使用 Workload Identity,则可以使用节点服务帐号以外的其他服务帐号来与 Google 服务通信。 您可以为 pod 创建一个 Kubernetes 服务帐号以运行 ESP 和 ESPv2,创建一个 Google 服务帐号并将 Kubernetes 服务帐号与该 Google 服务帐号相关联。

按照这些步骤将 Kubernetes 服务帐号与 Google 服务帐号相关联。

Google 服务帐号应具有所需的 IAM 角色。如果没有,请按照添加所需的 IAM 角色步骤操作。

配置 SSL 密钥和证书

容器原生负载平衡使用必须经过 TLS 加密的 HTTP2 LB。这需要将 TLS 证书部署到 GKE Ingress 和 ESPv2。您可以自带证书,也可以使用 Google 管理的 SSL 证书。本示例使用自签名证书。

  1. 使用 openssl 创建自签名证书和密钥。在系统要求您提供“公用名 (CN)”时,请务必输入相同的 FQDN bookstore.endpoints.MY_PROJECT_ID.cloud.goog。客户端使用该名称来验证服务器证书。

    openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout ./server.key -out ./server.crt
  2. 使用您的 SSL 密钥和证书创建 Kubernetes Secret。请注意,证书会复制到两个位置,即 server.crttls.crt,因为密钥同时提供给 GKE Ingress 和 ESPv2。GKE Ingress 会查找证书路径 tls.crt,ESPv2 会查找证书路径 server.crt

    kubectl create secret generic esp-ssl \
    --from-file=server.crt=./server.crt --from-file=server.key=./server.key \
    --from-file=tls.crt=./server.crt --from-file=tls.key=./server.key

将示例 API 和 ESPv2 部署到集群

如需将示例 gRPC 服务部署到集群,以便客户端能够使用该服务,请执行以下操作:

  1. git clone代码库,并打开以修改 grpc-bookstore.yaml 部署清单文件。
  2. SERVICE_NAME 替换为 Ingress 和 ESPv2 容器的 Endpoints 服务的名称。此名称与您在 api_config.yaml 文件的 name 字段中配置的名称相同。
    # Copyright 2016 Google Inc.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License
    
    # Use this file to deploy the container for the grpc-bookstore sample
    # and the container for the Extensible Service Proxy (ESP) to
    # Google Kubernetes Engine (GKE).
    
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: esp-grpc-bookstore
      annotations:
        kubernetes.io/ingress.class: "gce"
        kubernetes.io/ingress.allow-http: "false"
    spec:
      tls:
      - hosts:
        - SERVICE_NAME
        secretName: esp-ssl
      backend:
        serviceName: esp-grpc-bookstore
        servicePort: 443
    ---
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: esp-grpc-bookstore
    spec:
      healthCheck:
        type: HTTP2
        requestPath: /healthz
        port: 9000
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: esp-grpc-bookstore
      annotations:
        service.alpha.kubernetes.io/app-protocols: '{"esp-grpc-bookstore":"HTTP2"}'
        cloud.google.com/neg: '{"ingress": true, "exposed_ports": {"443":{}}}'
        cloud.google.com/backend-config: '{"default": "esp-grpc-bookstore"}'
    spec:
      ports:
      # Port that accepts gRPC and JSON/HTTP2 requests over TLS.
      - port: 443
        targetPort: 9000
        protocol: TCP
        name: esp-grpc-bookstore
      selector:
        app: esp-grpc-bookstore
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: esp-grpc-bookstore
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: esp-grpc-bookstore
      template:
        metadata:
          labels:
            app: esp-grpc-bookstore
        spec:
          volumes:
          - name: esp-ssl
            secret:
              secretName: esp-ssl
          containers:
          - name: esp
            image: gcr.io/endpoints-release/endpoints-runtime:2
            args: [
              "--listener_port=9000",
              "--service=SERVICE_NAME",
              "--rollout_strategy=managed",
              "--backend=grpc://127.0.0.1:8000",
              "--healthz=/healthz",
              "--ssl_server_cert_path=/etc/esp/ssl",
            ]
            ports:
              - containerPort: 9000
            volumeMounts:
            - mountPath: /etc/esp/ssl
              name:  esp-ssl
              readOnly: true
          - name: bookstore
            image: gcr.io/endpointsv2/python-grpc-bookstore-server:1
            ports:
              - containerPort: 8000
    

    --rollout_strategy=managed 选项可将 ESPv2 配置为使用最新部署的服务配置。如果指定此选项,则 ESPv2 会在您部署新服务配置后的一分钟内检测到更改并自动开始使用该服务配置。建议您指定此选项,而不是提供特定配置 ID 供 ESPv2 使用。如需详细了解 ESPv2 参数,请参阅 ESPv2 启动选项

    例如:

        spec:
          containers:
          - name: esp
            image: gcr.io/endpoints-release/endpoints-runtime:2
            args: [
              "--listener_port=9000",
              "--service=bookstore.endpoints.example-project-12345.cloud.goog",
              "--rollout_strategy=managed",
              "--backend=grpc://127.0.0.1:8000"
            ]
    
  3. 启动服务:
    kubectl create -f grpc-bookstore.yaml
    

如果收到错误消息,请参阅对 GKE 中的 Endpoints 进行问题排查

获取服务的外部 IP 地址

如需向示例 API 发送请求,您需要具备服务的外部 IP 地址。在容器中启动服务后,外部 IP 地址可能需要过几分钟才可以使用。

  1. 查看外部 IP 地址:

    kubectl get ingress

  2. 记下 EXTERNAL-IP 的值并将其保存在 SERVER_IP 环境变量中。外部 IP 地址用于将请求发送到示例 API。

    export SERVER_IP=YOUR_EXTERNAL_IP
    

向 API 发送请求

要向示例 API 发送请求,您可以使用以 Python 编写的示例 gRPC 客户端。

  1. 克隆托管 gRPC 客户端代码的 Git 代码库:

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
       

  2. 切换您的工作目录:

    cd python-docs-samples/endpoints/bookstore-grpc/
      

  3. 安装依赖项:

    pip install virtualenv
    virtualenv env
    source env/bin/activate
    python -m pip install -r requirements.txt
    

  4. 为自签名证书创建根 CA

    openssl x509 -in server.crt -out client.pem -outform PEM
      

  5. 向示例 API 发送一个请求:

    python bookstore_client.py --host SERVER_IP --port 443 \
    --servername bookstore.endpoints.MY_PROJECT_ID.cloud.goog --use_tls true --ca_path=client.pem
    

如果未成功收到响应,请参阅排查响应错误

您刚刚在 Endpoints 中部署并测试了一个 API!

清理

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

  1. 删除 API:

    gcloud endpoints services delete SERVICE_NAME
    

    SERVICE_NAME 替换为您的 API 名称。

  2. 删除 GKE 集群:

    gcloud container clusters delete NAME --zone ZONE
    

后续步骤