配置多集群 Service


本页面介绍了如何启用和使用多集群 Service (MCS)。如需详细了解 MCS 的工作原理及其优势,请参阅多集群 Service

Google Kubernetes Engine (GKE) MCS 功能扩展了 Kubernetes Service 的覆盖范围,使其超越集群边界,并且使您能够在多个 GKE 集群中发现和调用 Service。您可以导出现有 Service 或新 Service 的一部分。

使用 MCS 导出 Service 时,该 Service 可用于舰队中的所有集群。

由 MCS 管理的 Google Cloud 资源

MCS 可管理 Google Cloud 的以下组件:

  • Cloud DNS:MCS 可为您的舰队集群中每个导出的 Service 配置 Cloud DNS 区域和记录。这样,您可以连接到其他集群中运行的 Service。系统会根据您选择跨集群导出的 Service 创建、读取、更新和删除这些区域和记录。

  • 防火墙规则:MCS 可配置防火墙规则,让 Pod 能够在您的舰队中的集群之间相互通信。系统会根据您添加到舰队中的集群创建、读取、更新和删除防火墙规则。这些规则类似于 GKE 创建的规则,后者用于在 GKE 集群中的 Pod 之间实现通信。

  • Cloud Service Mesh:MCS 使用 Cloud Service Mesh 作为控制平面来跟踪端点及其在各集群中的健康状况。

要求

MCS 有以下要求:

  • MCS 仅支持从 Google Cloud 上的 VPC 原生 GKE 集群导出服务。如需了解详情,请参阅创建 VPC 原生集群。 您不能使用非 VPC 原生 GKE Standard 集群。

  • 集群之间的连接方式取决于集群是在同一 VPC 网络中还是在对等互连或共享 VPC 网络中运行。否则,对外部服务的调用将无法跨网络边界。

  • 虽然一个舰队可能跨多个 Google Cloud 项目和 VPC 网络,但必须从单个项目和单个 VPC 网络导出单个多集群服务。

  • 网络政策不支持 MCS。

  • 集群必须启用 HttpLoadBalancing 插件。确保已启用 HttpLoadBalancing 插件。HttpLoadBalancing 插件默认处于启用状态,不应停用。

价格

多集群服务包含在 GKE 集群管理费用中,不会产生额外的使用费用。您必须启用 Traffic Director API,但 MCS 不会产生任何 Cloud Service Mesh 端点费用。不需要 GKE Enterprise 许可即可使用 MCS。

准备工作

在开始之前,请确保您已执行以下任务:

  1. 安装 Google Cloud SDK

  2. 启用 Google Kubernetes Engine API:

    启用 Google Kubernetes Engine API

  3. 启用 MCS、舰队 (hub)、Resource Manager、Cloud Service Mesh 和 Cloud DNS API:

    gcloud services enable \
        multiclusterservicediscovery.googleapis.com \
        gkehub.googleapis.com \
        cloudresourcemanager.googleapis.com \
        trafficdirector.googleapis.com \
        dns.googleapis.com \
        --project=PROJECT_ID
    

    PROJECT_ID 替换为您打算在其中将集群注册到队列的项目中的项目 ID。

在项目中启用 MCS

MCS 要求将参与的 GKE 集群注册到同一舰队中。为舰队启用 MCS 功能后,任何集群都可以在该舰队的集群之间导出 Service。

虽然 MCS 确实需要向舰队注册,但并不要求您启用 GKE Enterprise 平台。

GKE Enterprise

如果在舰队宿主项目中启用了 GKE Enterprise API 作为使用其他 GKE Enterprise 组件的先决条件,则注册到项目舰队的所有集群都将根据 GKE Enterprise 价格收费。此价格模式允许您在所注册集群上使用所有 GKE Enterprise 功能,并按 vCPU 数量单独收费。您可以使用以下命令确认是否已启用 GKE Enterprise API:

gcloud services list --project=PROJECT_ID | grep anthos.googleapis.com

如果输出结果类似于以下内容,则说明启用了整个 GKE Enterprise 平台,并且注册到舰队的任何集群都将产生 GKE Enterprise 费用:

anthos.googleapis.com                        Anthos API

如果这不符合您的预期,请与项目管理员联系。

空输出表示未启用 GKE Enterprise。

在 GKE 集群上启用 MCS

  1. 为您的项目舰队启用 MCS 功能:

    gcloud container fleet multi-cluster-services enable \
        --project PROJECT_ID
    

    PROJECT_ID 替换为您打算在其中将集群注册到队列的项目中的项目 ID。 这是您的舰队宿主项目。

  2. 向舰队注册您的 GKE 集群。我们强烈建议您在启用适用于 GKE 的工作负载身份联合的情况下注册集群。如果您未启用适用于 GKE 的工作负载身份联合,则需要向 Google Cloud 服务账号注册集群以进行身份验证,然后完成对服务账号进行身份验证中的其他步骤。

    如需向适用于 GKE 的工作负载身份联合注册集群,请运行以下命令:

    gcloud container fleet memberships register MEMBERSHIP_NAME \
       --gke-cluster CLUSTER_LOCATION/CLUSTER_NAME \
       --enable-workload-identity \
       --project PROJECT_ID
    

    替换以下内容:

    • MEMBERSHIP_NAME:您选择用来唯一表示舰队中的集群的成员资格名称。通常,集群的舰队成员资格名称是集群的名称,但如果舰队中已经存在具有原始名称的其他集群,则可能需要指定新名称。
    • CLUSTER_LOCATION:集群所在的可用区或区域。
    • CLUSTER_NAME:集群的名称。
  3. 为 MCS 导入工具授予所需的 Identity and Access Management (IAM) 权限:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \
        --role "roles/compute.networkViewer"
    

    PROJECT_ID 替换为舰队宿主项目的 ID。

  4. 确保队列中的每个集群都有一个在其中共享 Service 的命名空间。如果需要,请使用以下命令创建命名空间:

    kubectl create ns NAMESPACE
    

    NAMESPACE 替换为命名空间的名称。

  5. 如需验证是否已启用 MCS,请运行以下命令:

    gcloud container fleet multi-cluster-services describe \
        --project PROJECT_ID
    

    输出内容类似如下:

    createTime: '2021-08-10T13:05:23.512044937Z'
    membershipStates:
      projects/PROJECT_ID/locations/global/memberships/MCS_NAME:
        state:
          code: OK
          description: Firewall successfully updated
          updateTime: '2021-08-10T13:14:45.173444870Z'
    name: projects/PROJECT_NAME/locations/global/features/multiclusterservicediscovery
    resourceState:
      state: ACTIVE
    spec: {}
    

    如果 state 的值不是 ACTIVE,请参阅问题排查部分。

对服务账号进行身份验证

如果您使用服务账号将 GKE 集群注册到一个舰队中,则需要执行其他步骤来对服务账号进行身份验证。MCS 会部署一个名为 gke-mcs-importer 的组件。此组件接收来自 Cloud Service Mesh 的端点更新,因此在启用 MCS 时,您需要授予服务账号从 Cloud Service Mesh 读取信息的权限。

使用服务账号时,您可以使用 Compute Engine 默认服务账号或您自己的节点服务账号:

使用 MCS

以下部分介绍如何使用 MCS。MCS 使用 Kubernetes 多集群服务 API

注册要导出的 Service

如需注册 Service 以导出到舰队中的其他集群,请完成以下步骤:

  1. 创建一个名为 export.yamlServiceExport 对象:

    # export.yaml
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
     namespace: NAMESPACE
     name: SERVICE_EXPORT_NAME
    

    替换以下内容:

    • NAMESPACEServiceExport 对象的命名空间。 此命名空间必须与您要导出的 Service 的命名空间相匹配。
    • SERVICE_EXPORT_NAME:集群中要导出到舰队内其他集群的 Service 的名称。
  2. 通过运行以下命令创建 ServiceExport 资源:

    kubectl apply -f export.yaml
    

Service 的初始导出需要大约五分钟才能同步到舰队中注册的集群。Service 导出后,后续端点同步会立即发生。

您可以从多个集群中导出同一 Service,以创建一个具有跨集群流量分配的高可用性多集群服务端点。在导出具有相同名称和命名空间的 Service 之前,请确保您希望以这种方式对它们进行分组。我们建议不要导出 defaultkube-system 命名空间中的服务,因为很可能会发生意外的名称冲突并可能产生意外分组。如果要导出五个以上具有相同名称和命名空间的服务,则导入服务的流量分配可能限制为五个导出的服务。

使用跨集群 Service

MCS 仅支持 ClusterSetIP 和无头 Service。只有 DNS“A”记录可用。

创建 ServiceExport 对象后,以下域名将解析为从任何舰队集群中的任何 Pod 导出的 Service:

 SERVICE_EXPORT_NAME.NAMESPACE.svc.clusterset.local

输出包括以下值:

  • SERVICE_EXPORT_NAMENAMESPACE:您在 ServiceExport 对象中定义的值。

对于 ClusterSetIP Service,网域会解析为 ClusterSetIP。您可以通过在创建 ServiceExport 对象的命名空间中定位 ServiceImport 对象来查找此值。系统会自动创建 ServiceImport 对象。

例如:

kind: ServiceImport
apiVersion: net.gke.io/v1
metadata:
 namespace: EXPORTED-SERVICE-NAMESPACE
 name: external-svc-SERVICE-EXPORT-TARGET
status:
 ports:
 - name: https
   port: 443
   protocol: TCP
   targetPort: 443
 ips: CLUSTER_SET_IP

MCS 会在将 Service 导入集群的过程中创建一个 Endpoints 对象。通过调查此对象,您可以监控 Service 导入的进度。如需查找 Endpoints 对象的名称,请在与导入的 Service 对应的 ServiceImport 对象上查找注解 net.gke.io/derived-service 的值。例如:

kind: ServiceImport
apiVersion: net.gke.io/v1
annotations: net.gke.io/derived-service: DERIVED_SERVICE_NAME
metadata:
 namespace: EXPORTED-SERVICE-NAMESPACE
 name: external-svc-SERVICE-EXPORT-TARGET

接下来,查找 Endpoints 对象以检查 MCS 是否已将端点传播到导入集群。Endpoints 对象在与 ServiceImport 对象相同的命名空间中创建,其名称存储在 net.gke.io/derived-service 注解中。例如:

kubectl get endpoints DERIVED_SERVICE_NAME -n NAMESPACE

替换以下内容:

  • DERIVED_SERVICE_NAMEServiceImport 对象上注解 net.gke.io/derived-service 的值。
  • NAMESPACEServiceExport 对象的命名空间。

您可以使用 Google Cloud 控制台中的 Cloud Service Mesh 信息中心详细了解端点的健康状况。

对于无头 Service,网域解析为导出集群中的端点的 IP 地址列表。每个具有主机名的后端 Pod 也可通过以下形式的域名独立寻址:

 HOSTNAME.MEMBERSHIP_NAME.LOCATION.SERVICE_EXPORT_NAME.NAMESPACE.svc.clusterset.local

输出包括以下值:

  • SERVICE_EXPORT_NAMENAMESPACE:您在 ServiceExport 对象中定义的值。
  • MEMBERSHIP_NAME:Pod 所属集群在舰队中的唯一标识符
  • LOCATION:成员资格的位置。成员资格为 global,或者其位置是 Pod 所在的区域或可用区之一,例如 us-central1
  • HOSTNAME:Pod 的主机名。

您还可以使用以下格式的域名,对主机名从注册了全球成员资格的集群中导出的后端 Pod 进行寻址:

HOSTNAME.MEMBERSHIP_NAME.SERVICE_EXPORT_NAME.NAMESPACE.svc.clusterset.local

停用 MCS

如需停用 MCS,请完成以下步骤:

  1. 对于舰队环境中的每个集群,请删除您创建的每个 ServiceExport 对象:

    kubectl delete serviceexport SERVICE_EXPORT_NAME \
        -n NAMESPACE
    

    替换以下内容:

    • SERVICE_EXPORT_NAME:ServiceExport 对象的名称。
    • NAMESPACEServiceExport 对象的命名空间。
  2. 验证 ServiceExport 是否会在 30 分钟内从列表中消失。

  3. 如果不需要为其他目的注册集群,请从舰队中取消注册集群

  4. 停用 multiclusterservicediscovery 功能:

    gcloud container fleet multi-cluster-services disable \
        --project PROJECT_ID
    

    PROJECT_ID 替换为您已在其中注册集群的项目的 ID。

  5. 停用 API for MCS:

    gcloud services disable multiclusterservicediscovery.googleapis.com \
        --project PROJECT_ID
    

    PROJECT_ID 替换为您已在其中注册集群的项目的 ID。

限制

以下限制不会强制执行,在某些情况下,您可以超出这些限制,具体取决于集群或项目中的负载以及端点流失率。不过,如果超出这些限制,您可能会遇到性能问题。

  • 导出集群:由命名空间名称标识的单个 Service 可以安全地从最多 5 个集群导出。如果超出此限制,可能只能将部分端点导入正在使用的集群中。您可以从不同的集群子集中导出不同的 Service。

  • 单个 Service 背后的 Pod 数:如果单个 Service 背后的 250 个 Pod 低于该值则安全。这与单个集群服务的限制相同。由于相对静态工作负载和少量多集群 Service,每个 Service 的端点数可能会显著增加到数千个端点。与单集群服务一样,所有端点上的 kube-proxy 都会监控每个节点。如果超出此限制(尤其是同时从多个集群导出时),则可能需要更大的节点。

  • 同时导出的多集群 Service 的数量:我们建议您同时导出最多 250 个唯一的 Service 端口(由 Service 的命名空间名称标识)并声明端口。例如,导出公开端口 80 和 443 的 Service 将计入 250 个唯一 Service 端口限制中的 2 个。从多个集群导出具有相同命名空间名称的服务将计为单个唯一服务。之前提到的 2 个端口服务在从 5 个集群同时导出时,仍会计入 2 个端口。每个多集群 Service 都会计入您的后端 Service 配额,并且每个导出集群或可用区都会创建一个网络端点组 (NEG)

Service 类型

MCS 仅支持 ClusterSetIP 和无头 Service。NodePort 和 LoadBalancer Service 不受支持,可能会导致意外行为。

将 IPmasq 代理与 MCS 搭配使用

当您使用默认 Pod IP 范围或其他未经过伪装的 Pod IP 范围时,MCS 会按预期运行。

如果您使用自定义 Pod IP 范围或自定义 IPmasq 代理 ConfigMap,则可以伪装 MCS 流量。这会阻止 MCS 运行,因为防火墙规则仅允许来自 Pod IP 的流量。

为避免此问题,您应该使用默认 Pod IP 范围,或在 IPmasq 代理 ConfigMapnonMasqueradeCIDRs 字段中指定所有 Pod IP 范围。如果您使用 Autopilot,或者必须使用非默认 Pod IP 范围,并且不能在 ConfigMap 中指定所有 Pod IP 范围,则应使用出站流量 NAT 政策来配置 IP 伪装

在 MCS 服务中重复使用端口号

在一个 MCS 服务中,即使协议不同,也不能重复使用同一端口号。

这适用于一个 Kubernetes Service 以及一个 MCS 服务的所有 Kubernetes Service。

在多个项目中具有集群的 MCS

如果某项服务已由舰队中名称和命名空间相同的不同项目中的其他集群导出,则您无法导出该服务。您可以访问舰队中的其他项目中的其他集群中的服务,但这些集群无法在同一命名空间中导出同一服务。

问题排查

以下部分为您提供针对 MCS 的问题排查提示。

查看 featureState

查看功能状态可帮助您确认 MCS 是否已成功配置。您可以使用以下命令来查看 MCS 功能状态:

gcloud container fleet multi-cluster-services describe

输出内容类似如下:

createTime: '2021-08-10T13:05:23.512044937Z'
membershipStates:
 projects/PROJECT_ID/locations/global/memberships/MCS_NAME:
   state:
     code: OK
     description: Firewall successfully updated
     updateTime: '2021-08-10T13:14:45.173444870Z'
name: projects/PROJECT_NAME/locations/global/features/multiclusterservicediscovery
resourceState:
 state: ACTIVE
spec: {}

进行问题排查的最有用字段是 codedescription

featureState 中的代码

代码表示成员相对于 MCS 的一般状态。您可以在 state.code 字段中找到这些字段。有三种可能的代码:

  • OK:成员资格已成功添加到 MCS,可供使用。

  • WARNING:MCS 正在调整成员资格设置。说明字段可提供有关导致此代码的原因的详细信息。

  • FAILED:此成员资格未添加到 MCS。舰队中代码为 OK 的其他成员资格不受此 FAILED 成员资格的影响。说明字段可提供有关导致此代码的原因的详细信息。

  • ERROR:此成员缺少资源。舰队中代码为 OK 的其他成员资格不受此 ERROR 成员资格的影响。说明字段可提供有关导致此代码的原因的详细信息。

featureState 中的说明

说明可提供有关 MCS 中的成员资格状态的详细信息。您可以在 state.description 字段中找到这些说明,并可以查看以下说明:

  • Firewall successfully created:此消息表示已成功创建和/或更新成员的防火墙规则。成员资格的代码为 OK

  • Firewall creation pending:此消息表示成员的防火墙规则正在等待创建或更新。成员资格的代码为 WARNING。更新和连接到防火墙规则待处理时添加的新多集群 Service 和成员资格时,此成员资格可能会遇到问题。

  • GKE Cluster missing:此消息表示已注册的 GKE 集群不可用或已删除。成员资格的代码为 ERROR。删除 GKE 集群后,此成员资格需要手动从舰队取消注册

  • Project that member lives in is missing required permissions and/or has not enabled all required APIs - additional setup steps are required:此消息表示存在内部 StatusForbidden (403) 错误,成员资格的代码为 FAILED。在以下情况下会发生此错误:

    • 您尚未在成员的项目中启用必要的 API

      如果成员集群与舰队位于不同项目中,请参阅跨项目设置,确保您已完成所有必要的步骤。如果您已完成所有步骤,请使用以下命令确保已在注册项目中启用以下 API:

      gcloud services enable multiclusterservicediscovery.googleapis.com --project PROJECT_ID
      gcloud services enable dns.googleapis.com --project PROJECT_ID
      gcloud services enable trafficdirector.googleapis.com --project PROJECT_ID
      gcloud services enable cloudresourcemanager.googleapis.com --project PROJECT_ID
      

      PROJECT_ID 替换为您已在其中注册集群的项目的 ID。

    • mcsdgkehub 服务账号在成员的项目中需要更多权限

      mcsdgkehub 服务账号应该已在拥有所有必要权限的舰队宿主项目中自动创建。如需验证服务账号是否存在,请运行以下命令:

      gcloud projects get-iam-policy PROJECT_ID | grep gcp-sa-mcsd
      gcloud projects get-iam-policy PROJECT_ID | grep gcp-sa-gkehub
      

      PROJECT_ID 替换为舰队宿主项目的 ID。

    这些命令应显示 mcsdgkehub 服务账号的完整名称。

  • Multiple VPCs detected in the hub - VPC must be peered with other VPCs for successful connectivity:当不同 VPC 中托管的集群注册到同一舰队时,会显示此消息。会员状态为 OK。集群的 VPC 网络由其 NetworkConfig 的网络定义。多集群 Service 需要平面网络,并且这些 VPC 必须主动对等互连,多集群 Service 才能正确连接。如需了解详情,请参阅将两个网络对等互连

  • Member does not exist in the same project as hub - additional setup steps are required, errors may occur if not completed.:此消息提醒您跨项目集群需要额外的设置步骤。会员状态为 OK。跨项目成员资格定义为与舰队属于不同项目的成员集群。如需了解详情,请参阅跨项目设置

  • Non-GKE clusters are currently not supported:此消息会提醒您 MCS 仅支持 GKE 集群。非 GKE 集群无法添加到 MCS。会员状态为 FAILED

已知问题

具有多个端口的 MCS 服务

GKE Dataplane V2 上具有多个 (TCP/UDP) 端口的多集群 Service 存在一个已知问题,即某些端点在数据平面中未编程。此问题会影响 1.26.3-gke.400 之前的 GKE 版本。

如需解决此问题,在使用 GKE Dataplane V2 时,请使用具有单个端口的多 MCS,而不是使用具有多个端口的单 MCS。

在一个 MCS 服务中重复使用的端口号

即使协议不同,您也不能重复使用 MCS 服务中的同一端口号。

这适用于一个 Kubernetes Service 以及一个 MCS 服务的所有 Kubernetes Service。

此行为将在即将推出的 MCS 版本中予以更正。

具有共享 VPC 的 MCS

使用 MCS 的当前实现时,如果您在同一共享 VPC 中部署多个舰队,则舰队之间会共享元数据。在一个舰队中创建 Service 时,Service 元数据会导出或导入到属于同一共享 VPC 且对用户可见的所有其他舰队。

此行为将在即将推出的 MCS 版本中予以更正。

健康检查使用默认端口而不是 containerPort

当您部署具有 targetPort 字段(引用 Deployment 中的已命名端口)的 Service 时,MCS 会配置健康检查的默认端口,而不是指定的 containerPort

为避免此问题,请使用 Service 字段 ports.targetPort 和 Deployment 字段 readinessProbe.httpGet.port 中的数值,而不是命名值。

此行为将在即将推出的 MCS 版本中予以更正。

后续步骤