部署多集群网关

本页面介绍如何部署 Kubernetes 网关资源以跨多个 Google Kubernetes Engine (GKE) 集群实现负载平衡。如需了解如何仅为单个 GKE 集群部署网关,请参阅部署网关

多集群网关

多集群网关是一种网关资源,用于跨多个 Kubernetes 集群进行流量负载平衡。在 GKE 中,gke-l7-gxlb-mcgke-l7-rilb-mc GatewayClass 会部署多集群网关,这些网关跨不同 GKE 集群、Kubernetes Namespace 提供 HTTP 路由、流量拆分、流量镜像、基于运行状况的故障切换等以及不同区域 多集群网关使基础架构管理员可以轻松、安全且可伸缩地管理跨多个集群和团队的应用网络。

多集群网关是一种网关资源,用于跨多个 Kubernetes 集群进行流量负载平衡。

本页面引入了三个示例,教您如何使用 GKE Gateway Controller 部署多集群网关:

  • 示例 1:外部多集群网关,跨两个 GKE 集群提供负载平衡以处理互联网流量。
  • 示例 2:适用于内部 VPC 流量的两个 GKE 集群之间的蓝绿基于权重的流量拆分和流量镜像。

每个示例均使用相同的商店和网站应用来模拟现实中的在线购物服务与网站服务自有场景由不同的团队和运营,并跨一系列共享 GKE 集群进行部署。每个示例均重点介绍多集群网关启用的不同拓扑和用例。

多集群网关需要一些环境准备才能部署。在继续操作之前,请按照启用多集群网关中的步骤操作:

  1. 部署 GKE 集群。

  2. 注册您的集群。

  3. 启用多集群 Service 和多集群 Gateway Controller。

最后,在您的环境中使用 GKE Gateway Controller 预览限制和已知问题前,请先查看相关内容。

多集群、多区域、外部网关

在本教程中,您将创建一个外部多集群网关,用于处理两个 GKE 集群中运行的整个应用中的外部流量。

store.example.com 部署在两个 GKE 集群中,并通过多集群网关向互联网公开

在以下步骤中,您将执行以下操作:

  1. 将示例 store 应用部署gke-west-1gke-east-1 集群。
  2. 在每个集群上配置 ServiceExport 资源,以将服务导出到您的队列。
  3. gke-l7-gxlb-mc 网关和 HTTPRoute 部署到配置集群 gke-west-1

部署应用和网关资源后,您可以使用基于路径的路由来控制两个 GKE 集群之间的流量:

  • /west 的请求将路由到 gke-west-1 集群中的 store pod。
  • /east 的请求将路由到 gke-east-1 集群中的 store pod。
  • 针对任何其他路径的请求会根据其运行状况、容量和与请求客户端的邻近程度路由到集群。

部署演示应用

  1. 启用多集群网关中部署的所有三个集群中创建 store 部署和命名空间:

    kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    kubectl apply --context gke-west-2 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    

    它会将以下资源部署到每个集群:

    namespace/store created
    deployment.apps/store created
    

    本页面中的所有示例均使用此步骤中部署的应用。在尝试任何其余步骤之前,请确保已在全部三个集群中部署该应用。此示例仅使用集群 gke-west-1gke-east-1,而 gke-west-2 则用于另一示例。

多集群 Service

Service 是将 Pod 公开给客户端的方式。由于 GKE Gateway Controller 使用容器原生负载平衡,因此不使用 ClusterIP 或 Kubernetes 负载平衡来访问 Pod。流量会直接从负载均衡器发送到 Pod IP。但是,Service 仍然发挥关键作用,是 Pod 分组的逻辑标识符。

多集群服务 (MCS) 既是一种适用于跨集群的 Service 的 API 标准,也是一个用于跨 GKE 集群发现服务的 GKE 控制器。多集群 Gateway Controller 使用 MCS API 资源将 Pod 分组为可跨多个集群访问的多个 Service 的对象。

Multi-cluster Services API 定义了以下自定义资源:

  • ServiceExport 会映射到 Kubernetes Service,并将该 Service 的端点导出到向队列注册的所有集群。当 Service 具有相应的 ServiceExport 时,表示该 Service 可以通过多集群网关进行寻址。
  • ServiceImport 由多集群 Service 控制器自动生成。ServiceExport 和 ServiceImport 成对提供。如果队列中存在 ServiceExport,则系统会创建相应的 ServiceImport,以允许从集群访问映射到 ServiceExport 的 Service。

导出 Service 的方式如下。gke-1 中存在一项存储服务,用于选择该集群中的一组 Pod。系统会在集群中创建 ServiceExport,该服务允许从集群中的其他集群访问 gke-1 中的 Pod。ServiceExport 将映射到并公开与 ServiceExport 资源具有相同名称和命名空间的服务。

apiVersion: v1
kind: Service
metadata:
  name: store
  namespace: store
spec:
  selector:
    app: store
  ports:
  - port: 8080
    targetPort: 8080
---
kind: ServiceExport
apiVersion: net.gke.io/v1
metadata:
  name: store
  namespace: store

下图显示了部署 ServiceExport 后会发生什么。如果存在 ServiceExport 和 Service 对,则多集群 Service 控制器会将相应的 ServiceImport 部署到机群中的每个 GKE 集群。ServiceImport 是每个集群中 store Service 的本地表示形式。这允许 gke-2 中的客户端 Pod 使用 ClusterIP 或无头服务访问 gke-1 中的 store Pod。以这种方式使用多集群服务时,可以在集群之间提供东-西负载平衡。如需使用多集群 Service 进行集群到集群负载平衡,请参阅配置多集群 Service

多集群服务可跨集群导出服务,从而实现集群间通信

多集群网关也使用 ServiceImport,但不用于集群到集群负载平衡。相反,网关将 ServiceImport 用作存在于另一个集群中或跨多个集群的 Service 的逻辑标识符。以下 HTTPRoute 引用 ServiceImport 而不是 Service 资源。通过引用 ServiceImport,这表示它正在将流量转发到在一个或多个集群上运行的一组后端 Pod。

kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
  name: store-route
  namespace: store
  labels:
    gateway: multi-cluster-gateway
spec:
  hostnames:
  - "store.example.com"
  rules:
  - forwardTo:
    - backendRef:
        group: net.gke.io
        kind: ServiceImport
        name: store
      port: 8080

下图显示了 HTTPRoute 如何将 store.example.com 流量路由到 gke-1gke-2 上的 store Pod。负载均衡器将它们视为一个后端池。如果来自其中一个集群的 Pod 运行状况不佳、无法访问或没有流量容量,则流量负载会平衡到另一个集群上剩余的 Pod。您可以使用 store Service 和 ServiceExport 添加或移除新集群。这将以透明方式添加或移除后端 Pod,而不会发生任何显式路由配置更改。

MCS 资源

导出 Service

此时,应用在这两个集群中运行。接下来,您将向每个集群部署 Service 和 ServiceExport,以公开和导出应用。

  1. 将以下清单保存到名为 store-west-service.yaml 的文件中:

    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-west-1
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-west-1
      namespace: store
    
  2. 将此清单部署到 gke-west-1

    kubectl apply -f store-west-service.yaml --context gke-west-1
    
  3. 将以下清单保存到名为 store-east-service.yaml 的文件中:

    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-east-1
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-east-1
      namespace: store
    
  4. 将此 ServiceExport 资源部署到 gke-east-1

    kubectl apply -f store-east-service.yaml --context gke-east-1 --namespace store
    
  5. 验证已在集群中创建了正确的 ServiceExport。

    kubectl get serviceexports --context CLUSTER_NAME --namespace store
    

    CLUSTER_NAME 替换为 gke-west-1gke-east-1。输出应类似于以下内容:

    # gke-west-1
    NAME           AGE
    store          2m40s
    store-west-1   2m40s
    
    # gke-east-1
    NAME           AGE
    store          2m25s
    store-east-1   2m25s
    

    这表明 store Service 跨两个集群包含 store Pod,而 store-west-1store-east-1 Service 仅在其各自的集群上包含 store Pod。这些重叠的服务用于跨多个集群或单个集群上的部分 Pod 定位 Pod。

  6. 几分钟后,请验证多集群 Service 控制器是否已跨集群组中的所有集群自动创建随附的 ServiceImports

    kubectl get serviceimports --context CLUSTER_NAME --namespace store
    

    CLUSTER_NAME 替换为 gke-west-1gke-east-1。输出应类似于以下内容:

    # gke-west-1
    NAME           TYPE           IP                  AGE
    store          ClusterSetIP   ["10.112.31.15"]    6m54s
    store-east-1   ClusterSetIP   ["10.112.26.235"]   5m49s
    store-west-1   ClusterSetIP   ["10.112.16.112"]   6m54s
    
    # gke-east-1
    NAME           TYPE           IP                  AGE
    store          ClusterSetIP   ["10.72.28.226"]   5d10h
    store-east-1   ClusterSetIP   ["10.72.19.177"]   5d10h
    store-west-1   ClusterSetIP   ["10.72.28.68"]    4h32m
    

这表明可以从集群中的所有两个集群访问所有三个 Service。但是,由于每个机组只有一个活跃配置集群,因此您只能在 gke-west-1 中部署引用这些 ServiceImport 的网关和 HTTPRoute。当配置集群中的 HTTPRoute 将这些 ServiceImport 引用为后端时,网关可以将流量转发到这些服务,无论它们是从哪个集群导出的。

部署网关和 HTTPRoute

部署应用后,您可以使用 gke-l7-gxlb-mc GatewayClass 配置网关。此网关会创建一个外部 HTTP(S) 负载均衡器,配置为在目标集群之间分配流量。

  1. 将以下 Gateway 网关清单保存到名为 external-http-gateway.yaml 的文件中:

    kind: Gateway
    apiVersion: networking.x-k8s.io/v1alpha1
    metadata:
      name: external-http
      namespace: store
    spec:
      gatewayClassName: gke-l7-gxlb-mc
      listeners:
      - protocol: HTTP
        port: 80
        routes:
          kind: HTTPRoute
          selector:
            matchLabels:
              gateway: external-http
    

    此示例使用 gke-l7-gxlb-mc GatewayClass,并通过标签 gateway: external-http 定位 HTTPRoutes

  2. 将该网关清单应用于此示例的 gke-west-1 配置集群:

    kubectl apply -f external-http-gateway.yaml --context gke-west-1 --namespace store
    
  3. 将以下 HTTPRoute 清单保存到名为 public-store-route.yaml 的文件中:

    kind: HTTPRoute
    apiVersion: networking.x-k8s.io/v1alpha1
    metadata:
      name: public-store-route
      namespace: store
      labels:
        gateway: external-http
    spec:
      hostnames:
      - "store.example.com"
      rules:
      - forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store
          port: 8080
      - matches:
        - path:
            type: Prefix
            value: /west
        forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-1
          port: 8080
      - matches:
        - path:
            type: Prefix
            value: /east
        forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-east-1
          port: 8080
    

部署后,此 HTTPRoute 将配置以下路由行为:

  • /west 的请求将路由到 gke-west-1 集群中的 store pod。
  • /east 的请求将路由到 gke-east-1 集群中的 store pod。
  • 针对任何其他路径的请求会根据其运行状况、容量和与请求客户端的邻近程度路由到集群。

HTTPRoute 支持使用重叠的 Service 路由到不同的集群子集

请注意,如果给定集群上的所有 Pod 运行状况不佳(或不存在),则流向 store Service 的流量将仅发送到实际具有 store Pod 的集群。如果指定集群上存在 ServiceExport 和 Service,则无法保证流量会发送到该集群。Pod 必须存在且以明确的方式响应负载均衡器健康检查,否则负载均衡器只会将流量发送到其他集群中运行状况良好的 store Pod。

  1. HTTPRoute 清单应用于此示例的 gke-1 配置集群:

    kubectl apply -f public-store-route.yaml --context gke-west-1 --namespace store
    

下图显示了您在这两个集群中部署的资源。由于 gke-west-1 是网关配置集群,因此 Gateway Controller 会监控该网关、HTTPRoute 和 ServiceImport。每个集群都有一个 store ServiceImport 以及另一个特定于该集群的 ServiceImport。两者都指向相同的 Pod。这使 HTTPRoute 能够指定应精确到何处的流量 - 发送到特定集群上的 store pod 或所有集群中的 store pod。

这是两个集群中的网关和多集群服务资源模型

请注意,这是一个逻辑资源模型,而不是流量的描述。流量路径直接从负载均衡器流向后端 Pod,与配置集群或集群没有直接关系。

验证部署

您现在可以向我们的多集群网关发出请求,并将流量分配到多个 GKE 集群。

  1. 通过检查网关状态和事件来验证网关和 HTTPRoute 是否已成功部署。

    kubectl describe gateway external-http --context gke-west-1 --namespace store
    

    您的输出应与以下内容类似:

    Spec:
      Gateway Class Name:  gke-l7-gxlb-mc
      Listeners:
        Port:      80
        Protocol:  HTTP
        Routes:
          Group:  networking.x-k8s.io
          Kind:   HTTPRoute
          Namespaces:
            From:  Same
          Selector:
            Match Labels:
              Gateway:  external-http
    Status:
      Addresses:
        Type:   IPAddress
        Value:  34.120.172.213
      Conditions:
        Last Transition Time:  1970-01-01T00:00:00Z
        Message:               Waiting for controller
        Reason:                NotReconciled
        Status:                False
        Type:                  Scheduled
    Events:
      Type     Reason  Age                     From                     Message
      ----     ------  ----                    ----                     -------
      Normal   UPDATE  29m (x2 over 29m)       global-gke-gateway-ctlr  store/external-http
      Normal   SYNC    59s (x9 over 29m)       global-gke-gateway-ctlr  SYNC on store/external-http was a success
    
  2. 网关部署成功后,从 external-http 网关检索外部 IP 地址。

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
    

    将以下步骤中的 VIP 替换为您收到的 IP 地址作为输出。

  3. 将流量发送到网域的根路径。这会将流量平衡到跨集群 gke-west-1gke-east-1store ServiceImport 流量。负载均衡器会将流量发送到离您最近的区域,因此您可能不会看到来自其他区域的响应。

    curl -H "host: store.example.com" http://VIP
    

    输出会确认 Pod 已从 gke-west-1 集群处理请求:

    {
    "cluster_name": "gke-east-1",
    "zone": "us-east1-b",
    "host_header": "store.example.com",
    "node_name": "gke-gke-east-1-default-pool-7aa30992-t2lp.c.agmsb-k8s.internal",
    "pod_name": "store-5f5b954888-dg22z",
    "pod_name_emoji": "⏭",
    "project_id": "agmsb-k8s",
    "timestamp": "2021-06-01T17:32:51"
    }
    
  4. 接下来将流量发送到 /west 路径。这会将流量路由到在 gke-west-1 集群上运行有 Pod 的 store-west ServiceImport。借助特定于集群的 ServiceImport(如 store-west),应用所有者可以明确将流量发送到特定集群,而不是让负载均衡器做出决策。

    curl -H "host: store.example.com" http://VIP/west
    

    输出会确认 Pod 已从 gke-west-1 集群处理请求:

    {
    "cluster_name": "gke-west-1", 
    "zone": "us-west1-a", 
    "host_header": "store.example.com",
    "node_name": "gke-gke-west-1-default-pool-65059399-2f41.c.agmsb-k8s.internal",
    "pod_name": "store-5f5b954888-d25m5",
    "pod_name_emoji": "🍾",
    "project_id": "agmsb-k8s",
    "timestamp": "2021-06-01T17:39:15",
    }
    
  5. 最后,将流量发送到 /east 路径。

    curl -H "host: store.example.com" http://VIP/east
    

    输出会确认 Pod 已从 gke-east-1 集群处理请求:

    {
    "cluster_name": "gke-east-1",
    "zone": "us-east1-b",
    "host_header": "store.example.com",
    "node_name": "gke-gke-east-1-default-pool-7aa30992-7j7z.c.agmsb-k8s.internal",
    "pod_name": "store-5f5b954888-hz6mw",
    "pod_name_emoji": "🧜🏾",
    "project_id": "agmsb-k8s",
    "timestamp": "2021-06-01T17:40:48"
    }
    

通过内部网关的蓝绿多集群路由

gke-l7-rilb GatewayClass 具有许多高级流量路由功能,包括流量拆分、标头匹配、标头操纵、流量镜像等。在此示例中,您将演示如何使用基于权重的流量拆分来明确控制两个 GKE 集群中的流量比例。

此示例介绍了服务所有者在将应用迁移到或扩展到新 GKE 集群时将采取的一些实际步骤。蓝绿部署的目标是通过多个确认新集群正常运行的验证步骤来降低风险。本示例介绍了四个部署阶段:

  1. 100% - 基于标头的 Canary 版使用 HTTP 标头路由仅发送测试或合成流量新集群。
  2. 100% - 镜像流量将用户流量镜像到 Canary 版集群。这会通过将所有用户流量复制到此集群来测试 Canary 集群的容量。
  3. 90% - 10%对 10% 的流量进行 Canary 拆分,以缓慢地将新集群公开给实时流量。
  4. 0%-100%完全切换到新集群,在以下情况下,可切换回观察到的任何错误。

两个 GKE 集群之间的蓝绿流量拆分

此示例与前一个示例类似,只是改为部署内部多集群网关。这将部署内部 HTTP(S) 负载均衡器,该负载均衡器只能从 VPC 内部以私密方式访问。您将使用在先前步骤中部署的集群和同一应用,但需要通过其他网关部署它们。

前提条件

以下示例基于部署外部多集群网关中的一些步骤。在继续此示例之前,请确保您已完成以下步骤:

  1. 启用多集群网关
  2. 部署演示应用

此示例使用您设置的 gke-west-1gke-west-2 集群。这些集群位于同一区域,因为 gke-l7-rilb-mc GatewayClass 是区域级的,仅支持同一区域内的集群后端。

  1. 部署每个集群所需的 Service 和 ServiceExport。如果您在上一个示例中部署了 Service 和 ServiceExport,则其中一些已经部署。

    kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-1-service.yaml
    kubectl apply --context gke-west-2 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-2-service.yaml
    

    它会为每个集群部署一组类似的资源:

    service/store created
    serviceexport.net.gke.io/store created
    service/store-west-2 created
    serviceexport.net.gke.io/store-west-2 created
    

部署网关

以下网关是通过 gke-l7-rilb-mc GatewayClass 创建的。这是一个区域网关,只能定位同一区域中的 GKE 集群。路由选择器 gateway: multi-cluster-gateway-ilb 与接下来部署的 HTTPRoute 资源所应用的相同。

  1. 如果您尚未为内部负载均衡器创建代理专用子网,请执行此操作。这是内部负载均衡器正常运行的必要条件。它会创建一个子网,用于为负载均衡器代理提供 IP 地址。在集群所在的区域中创建代理专用子网。

  2. 将以下网关清单保存到名为 internal-http-gateway.yaml 的文件中:

    kind: Gateway
    apiVersion: networking.x-k8s.io/v1alpha1
    metadata:
      name: internal-http
      namespace: store
    spec:
      gatewayClassName: gke-l7-rilb-mc
      listeners:
      - protocol: HTTP
        port: 80
        routes:
          kind: HTTPRoute
          selector:
            matchLabels:
              gateway: internal-http
    
  3. 将该网关清单应用于此示例的 gke-west-1 配置集群:

    kubectl apply -f internal-http-gateway.yaml --context gke-west-1 --namespace store
    
  4. 验证该网关是否已启动。您可以使用以下命令仅过滤来自该网关的事件:

    kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace store
    

    如果输出类似于以下内容,则表示网关部署成功:

    LAST SEEN   TYPE     REASON   OBJECT                  MESSAGE
    22m         Normal   ADD      gateway/internal-http   store/internal-http
    6m50s       Normal   UPDATE   gateway/internal-http   store/internal-http
    11m         Normal   SYNC     gateway/internal-http   store/internal-http
    3m26s       Normal   SYNC     gateway/internal-http   SYNC on store/internal-http was a success
    

基于标头的 Canary 版

借助基于标头的 Canary 测试,服务所有者可以匹配来自真实用户的合成测试流量。通过这种方法可以轻松地验证应用的基本网络是否正常运行,而无需向用户公开。

  1. 将以下 YAML 清单保存到名为 internal-route-stage-1.yaml 的文件:

    kind: HTTPRoute
    apiVersion: networking.x-k8s.io/v1alpha1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      hostnames:
      - "store.example.internal"
      rules:
    # Matches for env=canary and sends it to store-west-2 ServiceImport
      - matches:
        - headers:
            values:
              env: canary
        forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-2
          port: 8080
    # All other traffic goes to store-west-1 ServiceImport
      - forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-1
          port: 8080
    

部署后,此 HTTPRoute 将配置以下路由行为:

  • 对没有 env: canary HTTP 标头的 store.example.internal 的内部请求会路由到 gke-west-1 集群上的 store pod
  • 使用 env: canary HTTP 标头对 store.example.internal 的内部请求被路由到 gke-west-2 集群上的 store Pod

HTTPRoute 可让您根据 HTTP 标头路由到不同的集群

  1. internal-route-stage-1.yaml 应用于 gke-west-1 集群:

    kubectl apply -f internal-route-stage-1.yaml --context gke-west-1 --namespace store
    

将流量发送到网关 IP 地址,验证 HTTPRoute 是否正常运行。

  1. internal-http 检索内部 IP 地址。

    kubectl get gateway internal-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
    

    将以下步骤中的 VIP 替换为您收到的 IP 地址作为输出。

  1. 使用 env: canary HTTP 标头向网关发送请求。这将确认流量正路由到 gke-west-2。使用 GKE 集群所在 VPC 中的专用客户端,以确认请求是否正确路由。以下命令必须在对网关 IP 地址具有专用访问权限的机器上运行,否则将不起作用。

    curl -H "host: store.example.internal" -H "env: canary" http://VIP
    

    输出会确认请求由 gke-west-2 集群中的 Pod 处理:

    {
      "cluster_name": "gke-west-2", 
      "host_header": "store.example.internal",
      "node_name": "gke-gke-west-2-default-pool-4cde1f72-m82p.c.agmsb-k8s.internal",
      "pod_name": "store-5f5b954888-9kdb5",
      "pod_name_emoji": "😂",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-05-31T01:21:55",
      "zone": "us-west1-a"
    }
    

流量镜像

此阶段会将流量发送到预期集群,但还会将流量镜像到 Canary 集群。

  1. 将以下 YAML 清单保存到名为 internal-route-stage-2.yaml 的文件:

    kind: HTTPRoute
    apiVersion: networking.x-k8s.io/v1alpha1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      hostnames:
      - "store.example.internal"
      rules:
    # Sends all traffic to store-west-1 ServiceImport
      - forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-1
          port: 8080
    # Also mirrors all traffic to store-west-2 ServiceImport
        filters:
        - type: RequestMirror
          requestMirror:
            backendRef:
              group: net.gke.io
              kind: ServiceImport
              name: store-west-2
            port: 8080
    
  2. internal-route-stage-2.yaml 应用于 gke-west-1 集群:

    kubectl apply -f internal-route-stage-2.yaml --context gke-west-1 --namespace store
    
  3. 使用您的专用客户端向 internal-http 网关发送请求。使用 /mirror 路径,以便您可以在后续步骤中在应用日志中唯一标识此请求。

    curl -H "host: store.example.internal" http://VIP/mirror
    
  4. 输出会确认客户端收到来自 gke-west-1 集群中的 Pod 的响应:

    {
       "cluster_name": "gke-west-1", 
       "host_header": "store.example.internal",
       "node_name": "gke-gke-west-1-default-pool-65059399-ssfq.c.agmsb-k8s.internal",
       "pod_name": "store-5f5b954888-brg5w",
       "pod_name_emoji": "🎖",
       "project_id": "agmsb-k8s",
       "timestamp": "2021-05-31T01:24:51",
       "zone": "us-west1-a"
    }
    

    这可确认主集群是否正在响应流量。您仍然需要确认要迁移到的集群正在接收镜像流量。

  5. 检查 gke-west-2 集群上的 store pod 的应用日志。日志应确认 Pod 已收到来自负载均衡器的镜像流量。

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  6. 此输出确认 gke-west-2 集群上的 Pod 也收到了相同的请求,但它们对这些请求的响应不会发送回客户端。日志中显示的 IP 地址是与 Pod 通信的负载均衡器内部 IP 地址的 IP 地址。

    Found 2 pods, using pod/store-5f5b954888-gtldf
    2021-05-31 01:32:21,416 ... "GET /mirror HTTP/1.1" 200 -
    2021-05-31 01:32:23,323 ... "GET /mirror HTTP/1.1" 200 -
    2021-05-31 01:32:24,137 ... "GET /mirror HTTP/1.1" 200 -
    

使用镜像有助于确定流量负载如何影响应用性能,且不会以任何方式影响对客户端的响应。这可能是所有类型发布都需要的,但在发布可能会影响性能或负载的重大更改时非常有用。

流量拆分

流量拆分是发布新代码或安全地部署到新环境的最常用方法之一。服务所有者设置了发送到 Canary 后端的流量的明确百分比,该百分比通常只占总流量的很小一部分,以便可以在对真实用户请求具有可接受的风险量的情况下确定推出是否成功。

  1. 将以下 YAML 清单保存到名为 internal-route-stage-3.yaml 的文件:

    kind: HTTPRoute
    apiVersion: networking.x-k8s.io/v1alpha1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      hostnames:
      - "store.example.internal"
      rules:
    # 90% of traffic to store-west-1 ServiceImport
      - forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-1
          port: 8080
          weight: 90
    # 10% of traffic to store-west-2 ServiceImport
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-2
          port: 8080
          weight: 10
    
  2. internal-route-stage-3.yaml 应用于 gke-west-1 集群:

    kubectl apply -f internal-route-stage-3.yaml --context gke-west-1 --namespace store
    
  3. 使用您的专用客户端向 internal- http 网关发送连续 curl 请求。

    while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
    

    输出将类似于以下内容,表示发生了 90/10 流量拆分。

    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    ...
    

通过拆分少数流量,服务所有者可以检查应用的运行状况和响应。如果所有信号看起来都运行状况良好,则可以继续进行完整切换。

流量已切换

蓝绿迁移的最后一个阶段是完全切换到新集群并移除旧集群。如果服务所有者实际上将第二个集群添加到现有集群,则最后一步是不同的,因为最后一步会产生流量进入这两个集群。在这种情况下,建议使用单个 store ServiceImport,其中包含来自 gke-west-1gke-west-2 集群的 Pod。这样,负载均衡器就可以根据距离、运行状况和容量来决定“活跃-活跃”应用的流量去向。

  1. 将以下 YAML 清单保存到名为 internal-route-stage-4.yaml 的文件:

    kind: HTTPRoute
    apiVersion: networking.x-k8s.io/v1alpha1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      hostnames:
      - "store.example.internal"
      rules:
    # No traffic to the store-west-1 ServiceImport
      - forwardTo:
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-1
          port: 8080
          weight: 0
    # All traffic to the store-west-2 ServiceImport
        - backendRef:
            group: net.gke.io
            kind: ServiceImport
            name: store-west-2
          port: 8080
          weight: 100
    
  2. internal-route-stage-4.yaml 应用于 gke-west-1 集群:

    kubectl apply -f internal-route-stage-4.yaml --context gke-west-1 --namespace store
    
  3. 使用您的专用客户端向 internal- http 网关发送连续 curl 请求。

    while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
    

    输出将与此类似,表明所有流量现在都会转到 gke-west-2

    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    ...
    

最后一步完成从一个 GKE 集群到另一个 GKE 集群的完全蓝绿应用迁移。

后续步骤