使用连接器访问 Kubernetes API 对象

Google Kubernetes Engine (GKE) 集群由一个控制平面和多个称为节点的工作器机器组成。您可以在 GKE 集群中运行容器化 Kubernetes 工作负载。节点是运行容器化应用和其他工作负载的工作器机器,而控制平面是集群的统一端点。如需了解详情,请参阅 GKE 集群架构

Kubernetes API 服务器在控制平面上运行,允许您通过 Kubernetes API 调用与集群中的 Kubernetes 对象进行交互。对象是 Kubernetes 系统中的持久性实体,表示集群的状态。如需了解详情,请参阅 Kubernetes 文档中的 Kubernetes 中的对象以及链接到“Kubernetes API 参考文档”页面的 API 概览

本文档介绍如何在工作流中使用 Kubernetes API 连接器,向 GKE 集群控制平面上托管的 Kubernetes 服务端点发出请求。例如,您可以使用连接器来创建 Kubernetes Deployment、运行作业、管理 Pod 或通过代理访问已部署的应用。如需了解详情,请参阅 Kubernetes API 连接器概览

准备工作

在继续执行本文档中的任务之前,请确保您已完成某些前提条件。

启用 API

您必须先启用以下 API,然后才能使用 Kubernetes API 连接器访问 Kubernetes API 对象:

  • Google Kubernetes Engine API:使用 GKE 构建和管理基于容器的应用
  • Workflows API:用于管理工作流定义和执行;启用 Workflows API 会自动启用 Workflow Executions API

控制台

启用 API:

启用 API

gcloud

  1. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

    Cloud Shell 会话随即会在 Google Cloud 控制台的底部启动,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 且已为当前项目设置值的 Shell 环境。该会话可能需要几秒钟时间来完成初始化。

  2. 启用 API:

    gcloud services enable container.googleapis.com workflows.googleapis.com

创建服务账号

创建一个用户管理的服务帐号作为工作流的身份,并为其授予 Kubernetes Engine Developer (roles/container.developer) 角色,以便工作流可以访问集群内的 Kubernetes API 对象。

控制台

  1. 在 Google Cloud 控制台中,转到服务账号页面。

    转到“服务账号”

  2. 选择项目,然后点击创建服务账号

  3. 服务账号名称字段中,输入一个名称。Google Cloud 控制台会根据此名称填写服务帐号 ID 字段。

    服务账号说明字段中,输入说明。例如 Service account for Kubernetes API

  4. 点击创建并继续

  5. 选择角色列表中,过滤并选择 Kubernetes Engine Developer 角色。

  6. 点击继续

  7. 如需完成账号的创建过程,请点击完成

gcloud

  1. 创建服务账号:

    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME
    

    SERVICE_ACCOUNT_NAME 替换为服务帐号的名称。

  2. container.developer 角色授予您的服务账号:

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

    PROJECT_ID 替换为您的 Google Cloud 项目 ID。

请注意,您可以同时使用 IAM 和 Kubernetes 基于角色的访问权限控制 (RBAC) 来控制对 GKE 集群的访问权限:

  • IAM 并非特定于 Kubernetes;它为多种 Google Cloud 产品提供身份管理,并且主要在 Google Cloud 项目级别运行。

  • Kubernetes RBAC 是 Kubernetes 的核心组件,可让您为集群内的任何对象或对象类型创建和授予角色(一组权限)。如果您主要使用 GKE,并且需要针对集群中的每个对象和操作设置精细权限,那么 Kubernetes RBAC 是最佳选择。

如需了解更多信息,请参阅访问权限控制

创建 GKE 集群

如需使用 Kubernetes API 连接器,您必须已创建公共或专用 GKE 集群。在专用集群中,节点仅具有内部 IP 地址,这意味着节点和 Pod 默认与互联网隔离。如需了解详情,请参阅专用集群

您还可以指定操作模式,该模式为您提供不同级别的灵活性、责任和控制。例如,您可以创建一个 Autopilot 集群,这是 GKE 中的一种运维模式,在该模式下,Google 会管理您的集群配置,包括节点、伸缩、安全性和其他预配置设置。如需了解详情,请参阅选择 GKE 操作模式

如果您尚未创建 GKE 集群,可以向 GKE 集群部署一个 Web 服务器容器化应用。或者,要尝试按照本文档中的说明,您可以通过完成以下步骤来创建 Autopilot 集群。

控制台

  1. 在 Google Cloud 控制台中,转到 Kubernetes 集群页面。

    转到 Kubernetes 集群

  2. 点击 创建

  3. 如果系统要求您选择集群模式,请选择 Autopilot

  4. 集群基本信息部分,完成以下操作:

    1. 输入集群的名称,例如 hello-cluster
    2. 为您的集群选择一个区域,例如 us-central1
  5. 点击下一步:网络

  6. IPv4 网络访问权限部分中,如需创建具有可公开访问端点的集群,请选择公共集群

  7. 对于其他所有设置,请接受默认设置。

  8. 点击创建

集群创建可能需要几分钟才能完成。创建集群后,对勾标记 表示集群正在运行。

gcloud

运行以下命令:

gcloud container clusters create-auto CLUSTER_NAME \
    --location=LOCATION \
    --project=PROJECT_ID

替换以下内容:

  • CLUSTER_NAME:您的 GKE 集群的名称,例如 hello-cluster
  • LOCATION:集群的区域,例如 us-central1
  • PROJECT_ID:您的 Google Cloud 项目 ID

集群创建可能需要几分钟才能完成。创建集群后,输出应类似于以下内容:

Creating cluster hello-cluster...done.
Created [https://container.googleapis.com/v1/projects/MY_PROJECT/zones/us-central1/clusters/hello-cluster].
[...]
STATUS: RUNNING

使用连接器发送 HTTP 请求

您可以使用 Kubernetes API 连接器向 GKE 集群的控制平面发送 HTTP 请求。例如,以下工作流会在指定的 Kubernetes 集群中创建名为 nginx-deployment 的 Deployment。Deployment 描述了一种必需的状态;在本例中,使用 nginx:1.14.2 映像运行三个 Pod 并在端口 80 上公开其服务。(如果未指定,projectlocation 将默认为工作流的对应值。)

如需了解详情,请参阅 Kubernetes API 连接器函数 gke.request 的参考页面。

请注意以下几点:

部署工作流

在执行工作流之前,您必须先创建和部署该工作流。

控制台

  1. 在 Google Cloud 控制台中,前往工作流页面。

    进入 Workflows

  2. 点击 创建

  3. 输入新工作流的名称,例如 kubernetes-api-request

  4. 区域列表中,选择 us-central1

  5. 选择您之前创建的服务帐号

  6. 点击下一步

  7. 在工作流编辑器中,为工作流输入以下定义:

    YAML

    main:
      steps:
        - create_deployment:
            call: gke.request
            args:
              cluster_id: "CLUSTER_NAME"
              project: "PROJECT_ID"
              location: "LOCATION"
              method: "POST"
              path: "/apis/apps/v1/namespaces/default/deployments"
              body:
                kind: Deployment
                metadata:
                  name: nginx-deployment
                  labels:
                    app: nginx
                spec:
                  replicas: 3
                  selector:
                    matchLabels:
                      app: nginx
                  template:
                    metadata:
                      labels:
                        app: nginx
                    spec:
                      containers:
                        - name: nginx
                          image: nginx:1.14.2
                          ports:
                            - containerPort: 80
            result: result
        - returnResult:
            return: '${result}'

    JSON

    {
      "main": {
        "steps": [
          {
            "create_deployment": {
              "call": "gke.request",
              "args": {
                "cluster_id": "CLUSTER_NAME",
                "project": "PROJECT_ID",
                "location": "LOCATION",
                "method": "POST",
                "path": "/apis/apps/v1/namespaces/default/deployments",
                "body": {
                  "kind": "Deployment",
                  "metadata": {
                    "name": "nginx-deployment",
                    "labels": {
                      "app": "nginx"
                    }
                  },
                  "spec": {
                    "replicas": 3,
                    "selector": {
                      "matchLabels": {
                        "app": "nginx"
                      }
                    },
                    "template": {
                      "metadata": {
                        "labels": {
                          "app": "nginx"
                        }
                      },
                      "spec": {
                        "containers": [
                          {
                            "name": "nginx",
                            "image": "nginx:1.14.2",
                            "ports": [
                              {
                                "containerPort": 80
                              }
                            ]
                          }
                        ]
                      }
                    }
                  }
                }
              },
              "result": "result"
            }
          },
          {
            "returnResult": {
              "return": "${result}"
            }
          }
        ]
      }
    }
    

    替换以下内容:

    • CLUSTER_NAME:您的 GKE 集群的名称,例如 hello-cluster
    • PROJECT_ID:您的 Google Cloud 项目 ID
    • LOCATION:集群的区域,例如 us-central1
  8. 点击部署

gcloud

  1. 为工作流创建源代码文件:

    touch kubernetes-api-request.JSON_OR_YAML
    

    根据工作流的格式,将 JSON_OR_YAML 替换为 yamljson

  2. 在文本编辑器中,将以下工作流复制到源代码文件:

    YAML

    main:
      steps:
        - create_deployment:
            call: gke.request
            args:
              cluster_id: "CLUSTER_NAME"
              project: "PROJECT_ID"
              location: "LOCATION"
              method: "POST"
              path: "/apis/apps/v1/namespaces/default/deployments"
              body:
                kind: Deployment
                metadata:
                  name: nginx-deployment
                  labels:
                    app: nginx
                spec:
                  replicas: 3
                  selector:
                    matchLabels:
                      app: nginx
                  template:
                    metadata:
                      labels:
                        app: nginx
                    spec:
                      containers:
                        - name: nginx
                          image: nginx:1.14.2
                          ports:
                            - containerPort: 80
            result: result
        - returnResult:
            return: '${result}'

    JSON

    {
      "main": {
        "steps": [
          {
            "create_deployment": {
              "call": "gke.request",
              "args": {
                "cluster_id": "CLUSTER_NAME",
                "project": "PROJECT_ID",
                "location": "LOCATION",
                "method": "POST",
                "path": "/apis/apps/v1/namespaces/default/deployments",
                "body": {
                  "kind": "Deployment",
                  "metadata": {
                    "name": "nginx-deployment",
                    "labels": {
                      "app": "nginx"
                    }
                  },
                  "spec": {
                    "replicas": 3,
                    "selector": {
                      "matchLabels": {
                        "app": "nginx"
                      }
                    },
                    "template": {
                      "metadata": {
                        "labels": {
                          "app": "nginx"
                        }
                      },
                      "spec": {
                        "containers": [
                          {
                            "name": "nginx",
                            "image": "nginx:1.14.2",
                            "ports": [
                              {
                                "containerPort": 80
                              }
                            ]
                          }
                        ]
                      }
                    }
                  }
                }
              },
              "result": "result"
            }
          },
          {
            "returnResult": {
              "return": "${result}"
            }
          }
        ]
      }
    }
    

    替换以下内容:

    • CLUSTER_NAME:您的 GKE 集群的名称,例如 hello-cluster
    • LOCATION:集群的区域,例如 us-central1
  3. 部署工作流:

    gcloud workflows deploy kubernetes-api-request \
        --source=kubernetes-api-request.JSON_OR_YAML \
        --location=LOCATION \
        --service-account=SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com
    

执行工作流

成功部署工作流后,您就可以执行该工作流了。执行工作流会运行与工作流关联的当前工作流定义。

控制台

  1. 在 Google Cloud 控制台中,前往工作流页面。

    进入 Workflows

  2. 工作流页面上,选择您的工作流以转到其详情页面。

  3. Workflow details 页面上,点击 Execute

  4. 再次点击执行

  5. 输出窗格中查看工作流的结果。

    如果成功,执行状态应为 Succeeded,并且系统会返回响应的正文。

gcloud

执行工作流:

gcloud workflows run kubernetes-api-request \
    --location=LOCATION

如果成功,则状态应为 SUCCEEDED,并返回响应正文。

使用连接器运行 Kubernetes 作业

您可以使用 Kubernetes API 连接器在 GKE 集群中部署并运行 Kubernetes 作业。以下工作流将创建一个 Kubernetes 作业,该作业运行 Bash 脚本遍历一系列数字。工作流会等待 Kubernetes 作业完成,最长等待 90 秒;否则,将引发错误。如果 Job 完成,则之后会被删除。

请注意,如果作业的状态包含条件类型 Complete,则视为已完成。例如:

  "status": {
    "conditions": [
      {
        "type": "Complete",
        "status": "True"
      }
    ]
  }

如果 Job 失败,系统会返回 FailedJobError 标记。例如:

{
  "tags": ["FailedJobError"]
  "job": {...}
  "message":"Kubernetes job failed"
}

如需了解详情,请参阅以下 Kubernetes API 连接器函数的参考页面:

部署工作流

在执行工作流之前,您必须先创建和部署该工作流。

控制台

  1. 在 Google Cloud 控制台中,前往工作流页面。

    进入 Workflows

  2. 点击 创建

  3. 输入新工作流的名称,例如 kubernetes-api-job

  4. 区域列表中,选择 us-central1

  5. 选择您之前创建的服务帐号

  6. 点击下一步

  7. 在工作流编辑器中,为工作流输入以下定义:

    YAML

    main:
      steps:
        - init:
            assign:
              - project: "PROJECT_ID"
              - location: "LOCATION"
              - cluster_id: "CLUSTER_NAME"
              - job_name: "JOB_NAME"
              - namespace: "default"
        - create_job:
            call: gke.create_job
            args:
              cluster_id: '${cluster_id}'
              location: '${location}'
              project: '${project}'
              namespace: '${namespace}'
              job:
                apiVersion: batch/v1
                kind: Job
                metadata:
                  name: "${job_name}"
                spec:
                  template:
                    spec:
                      containers:
                        - name: counter
                          image: centos:7
                          command:
                            - "bin/bash"
                            - "-c"
                            - "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"
                      restartPolicy: Never
            result: job
        - wait_for_job:  # if job fails, raise error with "FailedJobError" tag and "job" field
            call: gke.await_job
            args:
              cluster_id: '${cluster_id}'
              job_name: '${job_name}'
              location: '${location}'
              project: '${project}'
              timeout: 90  # 90 seconds
            result: completed_job
        - cleanup_job:
            call: gke.delete_job
            args:
              cluster_id: '${cluster_id}'
              job_name: '${job_name}'
              location: '${location}'
              project: '${project}'
              query:
                propagationPolicy: "Foreground"  # delete child Pods
        - return_job:
            return: '${completed_job}'

    JSON

    {
      "main": {
        "steps": [
          {
            "init": {
              "assign": [
                {
                  "project": "PROJECT_ID"
                },
                {
                  "location": "LOCATION"
                },
                {
                  "cluster_id": "CLUSTER_NAME"
                },
                {
                  "job_name": "JOB_NAME"
                },
                {
                  "namespace": "default"
                }
              ]
            }
          },
          {
            "create_job": {
              "call": "gke.create_job",
              "args": {
                "cluster_id": "${cluster_id}",
                "location": "${location}",
                "project": "${project}",
                "namespace": "${namespace}",
                "job": {
                  "apiVersion": "batch/v1",
                  "kind": "Job",
                  "metadata": {
                    "name": "${job_name}"
                  },
                  "spec": {
                    "template": {
                      "spec": {
                        "containers": [
                          {
                            "name": "counter",
                            "image": "centos:7",
                            "command": [
                              "bin/bash",
                              "-c",
                              "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"
                            ]
                          }
                        ],
                        "restartPolicy": "Never"
                      }
                    }
                  }
                }
              },
              "result": "job"
            }
          },
          {
            "wait_for_job": {
              "call": "gke.await_job",
              "args": {
                "cluster_id": "${cluster_id}",
                "job_name": "${job_name}",
                "location": "${location}",
                "project": "${project}",
                "timeout": 90
              },
              "result": "completed_job"
            }
          },
          {
            "cleanup_job": {
              "call": "gke.delete_job",
              "args": {
                "cluster_id": "${cluster_id}",
                "job_name": "${job_name}",
                "location": "${location}",
                "project": "${project}",
                "query": {
                  "propagationPolicy": "Foreground"
                }
              }
            }
          },
          {
            "return_job": {
              "return": "${completed_job}"
            }
          }
        ]
      }
    }
    

    替换以下内容:

    • LOCATION:集群的区域,例如 us-central1
    • CLUSTER_NAME:您的 GKE 集群的名称,例如 hello-cluster
    • JOB_NAME:Kubernetes 作业的名称,例如 hello-job
  8. 点击部署

gcloud

  1. 为工作流创建源代码文件:

    touch kubernetes-api-job.JSON_OR_YAML
    

    根据工作流的格式,将 JSON_OR_YAML 替换为 yamljson

  2. 在文本编辑器中,将以下工作流复制到源代码文件:

    YAML

    main:
      steps:
        - init:
            assign:
              - project: "PROJECT_ID"
              - location: "LOCATION"
              - cluster_id: "CLUSTER_NAME"
              - job_name: "JOB_NAME"
              - namespace: "default"
        - create_job:
            call: gke.create_job
            args:
              cluster_id: '${cluster_id}'
              location: '${location}'
              project: '${project}'
              namespace: '${namespace}'
              job:
                apiVersion: batch/v1
                kind: Job
                metadata:
                  name: "${job_name}"
                spec:
                  template:
                    spec:
                      containers:
                        - name: counter
                          image: centos:7
                          command:
                            - "bin/bash"
                            - "-c"
                            - "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"
                      restartPolicy: Never
            result: job
        - wait_for_job:  # if job fails, raise error with "FailedJobError" tag and "job" field
            call: gke.await_job
            args:
              cluster_id: '${cluster_id}'
              job_name: '${job_name}'
              location: '${location}'
              project: '${project}'
              timeout: 90  # 90 seconds
            result: completed_job
        - cleanup_job:
            call: gke.delete_job
            args:
              cluster_id: '${cluster_id}'
              job_name: '${job_name}'
              location: '${location}'
              project: '${project}'
              query:
                propagationPolicy: "Foreground"  # delete child Pods
        - return_job:
            return: '${completed_job}'

    JSON

    {
      "main": {
        "steps": [
          {
            "init": {
              "assign": [
                {
                  "project": "PROJECT_ID"
                },
                {
                  "location": "LOCATION"
                },
                {
                  "cluster_id": "CLUSTER_NAME"
                },
                {
                  "job_name": "JOB_NAME"
                },
                {
                  "namespace": "default"
                }
              ]
            }
          },
          {
            "create_job": {
              "call": "gke.create_job",
              "args": {
                "cluster_id": "${cluster_id}",
                "location": "${location}",
                "project": "${project}",
                "namespace": "${namespace}",
                "job": {
                  "apiVersion": "batch/v1",
                  "kind": "Job",
                  "metadata": {
                    "name": "${job_name}"
                  },
                  "spec": {
                    "template": {
                      "spec": {
                        "containers": [
                          {
                            "name": "counter",
                            "image": "centos:7",
                            "command": [
                              "bin/bash",
                              "-c",
                              "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"
                            ]
                          }
                        ],
                        "restartPolicy": "Never"
                      }
                    }
                  }
                }
              },
              "result": "job"
            }
          },
          {
            "wait_for_job": {
              "call": "gke.await_job",
              "args": {
                "cluster_id": "${cluster_id}",
                "job_name": "${job_name}",
                "location": "${location}",
                "project": "${project}",
                "timeout": 90
              },
              "result": "completed_job"
            }
          },
          {
            "cleanup_job": {
              "call": "gke.delete_job",
              "args": {
                "cluster_id": "${cluster_id}",
                "job_name": "${job_name}",
                "location": "${location}",
                "project": "${project}",
                "query": {
                  "propagationPolicy": "Foreground"
                }
              }
            }
          },
          {
            "return_job": {
              "return": "${completed_job}"
            }
          }
        ]
      }
    }
    

    替换以下内容:

    • LOCATION:集群的区域,例如 us-central1
    • CLUSTER_NAME:您的 GKE 集群的名称,例如 hello-cluster
    • JOB_NAME:Kubernetes 作业的名称,例如 hello-job
  3. 部署工作流:

    gcloud workflows deploy kubernetes-api-job \
        --source=kubernetes-api-job.JSON_OR_YAML \
        --location=LOCATION \
        --service-account=SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com
    

执行工作流

成功部署工作流后,您就可以执行该工作流了。执行工作流会运行与工作流关联的当前工作流定义。

控制台

  1. 在 Google Cloud 控制台中,前往工作流页面。

    进入 Workflows

  2. 工作流页面上,选择您的工作流以转到其详情页面。

  3. Workflow details 页面上,点击 Execute

  4. 再次点击执行

    工作流执行可能需要几分钟时间。

  5. 输出窗格中查看工作流的结果。

    结果应类似于以下内容:

    {
    ...
      },
      "status": {
        "completionTime": "2023-10-31T17:04:32Z",
        "conditions": [
          {
            "lastProbeTime": "2023-10-31T17:04:33Z",
            "lastTransitionTime": "2023-10-31T17:04:33Z",
            "status": "True",
            "type": "Complete"
          }
        ],
        "ready": 0,
        "startTime": "2023-10-31T17:04:28Z",
        "succeeded": 1,
        "uncountedTerminatedPods": {}
      }
    }
    

gcloud

执行工作流:

gcloud workflows run kubernetes-api-job \
    --location=LOCATION

工作流执行可能需要几分钟时间。结果应类似于以下内容:

{
...
  },
  "status": {
    "completionTime": "2023-10-31T17:04:32Z",
    "conditions": [
      {
        "lastProbeTime": "2023-10-31T17:04:33Z",
        "lastTransitionTime": "2023-10-31T17:04:33Z",
        "status": "True",
        "type": "Complete"
      }
    ],
    "ready": 0,
    "startTime": "2023-10-31T17:04:28Z",
    "succeeded": 1,
    "uncountedTerminatedPods": {}
  }
}

后续步骤