部署多叢集閘道


本頁說明如何部署 Kubernetes Gateway 資源,在多個 Google Kubernetes Engine (GKE) 叢集 (或機群) 之間平衡 Ingress 流量負載。部署多叢集閘道前,請參閱「啟用多叢集閘道」一文,準備好環境。

如要部署閘道,將 Ingress 流量負載平衡至單一 GKE 叢集,請參閱「部署閘道」。

多叢集閘道

多叢集閘道是一種閘道資源,可跨多個 Kubernetes 叢集進行流量負載平衡。在 GKE 中,gke-l7-global-external-managed-mcgke-l7-regional-external-managed-mcgke-l7-rilb-mcgke-l7-gxlb-mc GatewayClass 會部署多叢集閘道,在不同 GKE 叢集、Kubernetes 命名空間和不同區域之間,提供 HTTP 路由、流量分割、流量鏡像、以健康狀態為準的容錯移轉等功能。基礎架構管理員可透過多叢集閘道,輕鬆、安全且大規模地管理多個叢集和團隊的應用程式網路。

多叢集閘道是一種閘道資源,可在多個 Kubernetes 叢集之間平衡流量負載。

本頁面提供三個範例,說明如何使用 GKE Gateway 控制器部署多叢集 Gateway:

  • 範例 1:外部多叢集閘道,可為兩個 GKE 叢集的網際網路流量提供負載平衡。
  • 範例 2:第 7 層跨區域閘道。
  • 範例 3:在兩個 GKE 叢集之間,根據權重分配流量,並鏡像處理內部 VPC 流量,以進行藍綠部署。
  • 示例 4:以容量為基礎的閘道,可根據不同後端的容量上限,將要求負載平衡至這些後端。

每個範例都會使用相同的 storesite 應用程式,模擬實際情況:線上購物服務和網站服務由不同團隊擁有及營運,並部署在共用 GKE 叢集的機群中。每個範例都著重於多叢集閘道支援的不同拓撲和用途。

部署多叢集閘道前,需要先完成一些環境準備作業。請先按照「啟用多叢集閘道」一節中的步驟操作,再繼續進行:

  1. 部署 GKE 叢集。

  2. 將叢集註冊至機群。

  3. 啟用多叢集服務和多叢集閘道控制器。

最後,請先查看 GKE Gateway 控制器的限制和已知問題,再於環境中使用。

多叢集、多區域、外部閘道

在本教學課程中,您將建立外部多叢集閘道,為在兩個 GKE 叢集中執行的應用程式提供外部流量服務。

store.example.com 部署在兩個 GKE 叢集,並透過多叢集閘道公開至網際網路

您將在後續步驟執行下列操作:

  1. 將範例store應用程式部署至 gke-west-1gke-east-1 叢集。
  2. 在每個叢集上設定要匯出至機群的服務 (多叢集服務)。
  3. 將外部多叢集閘道和 HTTPRoute 部署至設定叢集 (gke-west-1)。

部署應用程式和閘道資源後,您可以使用路徑導向功能,控管兩個 GKE 叢集之間的流量:

  • /west 的要求會轉送到 gke-west-1 叢集中的 store Pod。
  • /east 的要求會轉送到 gke-east-1 叢集中的 store Pod。
  • 系統會根據叢集的健康狀態、容量,以及與要求用戶端的距離,將其他路徑的要求轉送至任一叢集。

部署示範應用程式

  1. 在「啟用多叢集閘道」中部署的所有三個叢集中,建立 store Deployment 和 Namespace:

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

    並將下列資源部署至每個叢集:

    namespace/store created
    deployment.apps/store created
    

    本頁面的所有範例都使用這個步驟中部署的應用程式。請務必先在所有三個叢集部署應用程式,再嘗試執行其餘步驟。本範例只使用叢集 gke-west-1gke-east-1gke-west-2 則用於其他範例。

多叢集 Service

Service 可讓 Pod 向用戶端公開。由於 GKE Gateway 控制器使用容器原生負載平衡,因此不會使用 ClusterIP 或 Kubernetes 負載平衡來連線至 Pod。流量會直接從負載平衡器傳送至 Pod IP 位址。不過,服務仍是 Pod 分組的邏輯識別碼,扮演重要角色。

多叢集服務 (MCS) 是服務的 API 標準,可跨越叢集,而 GKE 控制器則可在 GKE 叢集之間提供服務探索功能。多叢集 Gateway 控制器會使用 MCS API 資源,將 Pod 分組到可跨多個叢集定址或橫跨多個叢集的 Service 中。

多叢集服務 API 定義下列自訂資源:

  • ServiceExports 會對應至 Kubernetes 服務,並將該服務的端點匯出至註冊至機群的所有叢集。如果 Service 具有對應的 ServiceExport,表示多叢集閘道可以處理該 Service。
  • 多叢集服務控制器會自動產生 ServiceImports。ServiceExport 和 ServiceImport 會成對出現。如果機群中存在 ServiceExport,系統就會建立對應的 ServiceImport,允許從各個叢集存取對應至 ServiceExport 的 Service。

匯出服務的運作方式如下:商店服務存在於 gke-west-1 中,可選取該叢集中的一組 Pod。系統會在叢集中建立 ServiceExport,讓機群中的其他叢集可以存取 gke-west-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 服務的本機表示法。這會啟用 gke-east-1 中的 client Pod,以便使用 ClusterIP 或無標題服務連線至 gke-west-1 中的 store Pod。以這種方式使用時,多叢集服務會在叢集之間提供東西向負載平衡,無須內部 LoadBalancer 服務。如要使用多叢集服務進行叢集間的負載平衡,請參閱「設定多叢集服務」。

多叢集服務會匯出不同叢集的服務,讓叢集之間可以通訊

多叢集閘道也會使用 ServiceImport,但不是用於叢集間的負載平衡。而是使用 ServiceImports 做為服務的邏輯 ID,該服務存在於其他叢集,或跨越多個叢集。下列 HTTPRoute 參照的是 ServiceImport,而非 Service 資源。參照 ServiceImport 時,這表示服務會將流量轉送至一或多個叢集中執行的後端 Pod 群組。

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: store-route
  namespace: store
  labels:
    gateway: multi-cluster-gateway
spec:
  parentRefs:
  - kind: Gateway
    namespace: store
    name: external-http
  hostnames:
  - "store.example.com"
  rules:
  - backendRefs:
    - group: net.gke.io
      kind: ServiceImport
      name: store
      port: 8080

下圖顯示 HTTPRoute 如何將 store.example.com 流量轉送至 gke-west-1gke-east-1 上的 store Pod。負載平衡器會將這些後端視為一個後端集區。如果其中一個叢集的 Pod 狀況不佳、無法連線或沒有流量容量,流量負載就會平衡到另一個叢集的其餘 Pod。您可以使用 store 服務和 ServiceExport 新增或移除叢集。這會透明地新增或移除後端 Pod,而不會有任何明確的路由設定變更。

MCS 資源

出口服務

此時,應用程式會在兩個叢集上執行。接下來,您將在每個叢集中部署 Service 和 ServiceExport,藉此公開及匯出應用程式。

  1. 將下列資訊清單套用至 gke-west-1 叢集,建立 storestore-west-1 服務和 ServiceExports:

    cat << EOF | kubectl apply --context gke-west-1 -f -
    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
    EOF
    
  2. 將下列資訊清單套用至 gke-east-1 叢集,建立 storestore-east-1 服務和 ServiceExports:

    cat << EOF | kubectl apply --context gke-east-1 -f -
    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
    EOF
    
  3. 確認叢集中已建立正確的 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。

  4. 幾分鐘後,請確認多叢集服務控制器是否已在機群的所有叢集中,自動建立隨附的 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
    

    這表示機群中兩個叢集都能存取這三項服務。不過,由於每個車隊只有一個有效的設定叢集,因此您只能在 gke-west-1 中部署參照這些 ServiceImport 的 Gateway 和 HTTPRoute。當設定叢集中的 HTTPRoute 將這些 ServiceImport 參照為後端時,無論這些服務是從哪個叢集匯出,Gateway 都能將流量轉送至這些服務。

部署 Gateway 和 HTTPRoute

應用程式部署完成後,您可以使用 gke-l7-global-external-managed-mc GatewayClass 設定 Gateway。這個閘道會建立外部應用程式負載平衡器,並設定將流量分配至目標叢集。

  1. 將下列 Gateway 資訊清單套用至設定叢集,在本例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
      namespace: store
    spec:
      gatewayClassName: gke-l7-global-external-managed-mc
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    EOF
    

    這項 Gateway 設定會部署外部應用程式負載平衡器資源,並採用下列命名慣例:gkemcg1-NAMESPACE-GATEWAY_NAME-HASH

    使用這項設定建立的預設資源如下:

    • 1 個負載平衡器:gkemcg1-store-external-http-HASH
    • 1 個公開 IP 位址:gkemcg1-store-external-http-HASH
    • 1 項轉送規則:gkemcg1-store-external-http-HASH
    • 2 項後端服務:
      • 預設 404 後端服務:gkemcg1-store-gw-serve404-HASH
      • 預設 500 後端服務:gkemcg1-store-gw-serve500-HASH
    • 1 項健康檢查:
      • 預設 404 健康狀態檢查:gkemcg1-store-gw-serve404-HASH
    • 0 個匯款規則 (URLmap 為空白)

    在這個階段,任何對 GATEWAY_IP:80 的要求都會導致預設頁面顯示以下訊息:fault filter abort

  2. 將下列 HTTPRoute 資訊清單套用至設定叢集,在本範例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: public-store-route
      namespace: store
      labels:
        gateway: external-http
    spec:
      hostnames:
      - "store.example.com"
      parentRefs:
      - name: external-http
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /west
        backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-west-1
          port: 8080
      - matches:
        - path:
            type: PathPrefix
            value: /east
        backendRefs:
          - group: net.gke.io
            kind: ServiceImport
            name: store-east-1
            port: 8080
      - backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store
          port: 8080
    EOF
    

    在這個階段,任何對 GATEWAY_IP:80 的要求都會導致預設頁面顯示以下訊息:fault filter abort

    部署後,這個 HTTPRoute 會設定下列轉送行為:

    • /west 的要求會路由到 gke-west-1 叢集中的 store Pod,因為 store-west-1 ServiceExport 選取的 Pod 只存在於 gke-west-1 叢集。
    • /east 的要求會路由到 gke-east-1 叢集中的 store Pod,因為 store-east-1 ServiceExport 選取的 Pod 只存在於 gke-east-1 叢集。
    • 系統會根據健康狀態、容量和與要求用戶端的距離,將任何其他路徑的要求轉送至任一叢集中的 store Pod。
    • GATEWAY_IP:80 的要求會導致預設頁面顯示以下訊息:fault filter abort

    HTTPRoute 可透過重疊的服務,將流量導向不同的叢集子集

    請注意,如果特定叢集上的所有 Pod 都不正常 (或不存在),則傳送至 store 服務的流量只會傳送至實際有 store Pod 的叢集。特定叢集上存在 ServiceExport 和 Service,並不保證流量會傳送至該叢集。Pod 必須存在,且對負載平衡器健康狀態檢查有正面回應,否則負載平衡器只會將流量傳送至其他叢集中健康狀態良好的 store Pod。

    系統會使用這項設定建立新資源:

    • 3 項後端服務:
      • store後端服務:gkemcg1-store-store-8080-HASH
      • store-east-1後端服務:gkemcg1-store-store-east-1-8080-HASH
      • store-west-1後端服務:gkemcg1-store-store-west-1-8080-HASH
    • 3 項健康檢查:
      • store健康狀態檢查:gkemcg1-store-store-8080-HASH
      • store-east-1健康狀態檢查:gkemcg1-store-store-east-1-8080-HASH
      • store-west-1健康狀態檢查:gkemcg1-store-store-west-1-8080-HASH
    • URLmap 中的 1 項轉送規則:
      • store.example.com 匯款規則:
      • 1 位主辦人:store.example.com
      • 多個 matchRules,可將流量轉送至新的後端服務

下圖顯示您在兩個叢集中部署的資源。由於 gke-west-1 是 Gateway 設定叢集,因此 Gateway 控制器會監控這個叢集中的 Gateway、HTTPRoute 和 ServiceImport。每個叢集都有一個 store ServiceImport,以及另一個專屬於該叢集的 ServiceImport。兩者都指向相同的 Pod。這項功能可讓 HTTPRoute 準確指定流量的去向,例如特定叢集上的 store Pod,或是所有叢集中的 store Pod。

這是兩個叢集之間的閘道和多叢集服務資源模型

請注意,這是邏輯資源模型,並非流量流程的描述。流量路徑會直接從負載平衡器傳送至後端 Pod,與哪個叢集是設定叢集沒有直接關係。

驗證部署作業

您現在可以向多叢集閘道發出要求,並在兩個 GKE 叢集之間分配流量。

  1. 檢查閘道狀態和事件,確認閘道和 HTTPRoute 是否已成功部署。

    kubectl describe gateways.gateway.networking.k8s.io external-http --context gke-west-1 --namespace store
    

    輸出內容應類似以下所示:

    Name:         external-http
    Namespace:    store
    Labels:       <none>
    Annotations:  networking.gke.io/addresses: /projects/PROJECT_NUMBER/global/addresses/gkemcg1-store-external-http-laup24msshu4
                  networking.gke.io/backend-services:
                    /projects/PROJECT_NUMBER/global/backendServices/gkemcg1-store-gw-serve404-80-n65xmts4xvw2, /projects/PROJECT_NUMBER/global/backendServices/gke...
                  networking.gke.io/firewalls: /projects/PROJECT_NUMBER/global/firewalls/gkemcg1-l7-default-global
                  networking.gke.io/forwarding-rules: /projects/PROJECT_NUMBER/global/forwardingRules/gkemcg1-store-external-http-a5et3e3itxsv
                  networking.gke.io/health-checks:
                    /projects/PROJECT_NUMBER/global/healthChecks/gkemcg1-store-gw-serve404-80-n65xmts4xvw2, /projects/PROJECT_NUMBER/global/healthChecks/gkemcg1-s...
                  networking.gke.io/last-reconcile-time: 2023-10-12T17:54:24Z
                  networking.gke.io/ssl-certificates:
                  networking.gke.io/target-http-proxies: /projects/PROJECT_NUMBER/global/targetHttpProxies/gkemcg1-store-external-http-94oqhkftu5yz
                  networking.gke.io/target-https-proxies:
                  networking.gke.io/url-maps: /projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-store-external-http-94oqhkftu5yz
    API Version:  gateway.networking.k8s.io/v1beta1
    Kind:         Gateway
    Metadata:
      Creation Timestamp:  2023-10-12T06:59:32Z
      Finalizers:
        gateway.finalizer.networking.gke.io
      Generation:        1
      Resource Version:  467057
      UID:               1dcb188e-2917-404f-9945-5f3c2e907b4c
    Spec:
      Gateway Class Name:  gke-l7-global-external-managed-mc
      Listeners:
        Allowed Routes:
          Kinds:
            Group:  gateway.networking.k8s.io
            Kind:   HTTPRoute
          Namespaces:
            From:  Same
        Name:      http
        Port:      80
        Protocol:  HTTP
    Status:
      Addresses:
        Type:   IPAddress
        Value:  34.36.127.249
      Conditions:
        Last Transition Time:  2023-10-12T07:00:41Z
        Message:               The OSS Gateway API has deprecated this condition, do not depend on it.
        Observed Generation:   1
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
        Last Transition Time:  2023-10-12T07:00:41Z
        Message:
        Observed Generation:   1
        Reason:                Accepted
        Status:                True
        Type:                  Accepted
        Last Transition Time:  2023-10-12T07:00:41Z
        Message:
        Observed Generation:   1
        Reason:                Programmed
        Status:                True
        Type:                  Programmed
        Last Transition Time:  2023-10-12T07:00:41Z
        Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
        Observed Generation:   1
        Reason:                Ready
        Status:                True
        Type:                  Ready
      Listeners:
        Attached Routes:  1
        Conditions:
          Last Transition Time:  2023-10-12T07:00:41Z
          Message:
          Observed Generation:   1
          Reason:                Programmed
          Status:                True
          Type:                  Programmed
          Last Transition Time:  2023-10-12T07:00:41Z
          Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
          Observed Generation:   1
          Reason:                Ready
          Status:                True
          Type:                  Ready
        Name:                    http
        Supported Kinds:
          Group:  gateway.networking.k8s.io
          Kind:   HTTPRoute
    Events:
      Type    Reason  Age                    From                   Message
      ----    ------  ----                   ----                   -------
      Normal  UPDATE  35m (x4 over 10h)      mc-gateway-controller  store/external-http
      Normal  SYNC    4m22s (x216 over 10h)  mc-gateway-controller  SYNC on store/external-http was a success
    
  2. 閘道部署完成後,請從 external-http 閘道擷取外部 IP 位址。

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

    在下列步驟中,將 VIP 替換為您收到的輸出 IP 位址。

  3. 將流量傳送至網域的根路徑。這會將流量負載平衡至跨叢集 storegke-west-1 的 ServiceImport。gke-east-1負載平衡器會將流量傳送到離您最近的區域,因此您可能不會看到其他區域的回應。

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

    輸出內容會確認要求是由叢集的 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-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 路徑。這會將流量轉送至 store-west-1 ServiceImport,該 ServiceImport 只會在 gke-west-1 叢集上執行 Pod。叢集專用的 ServiceImport (例如 store-west-1) 可讓應用程式擁有者明確將流量傳送至特定叢集,而不是讓負載平衡器做出決定。

    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 叢集之間提供第 7 層內部負載平衡。這些閘道會使用 gke-l7-cross-regional-internal-managed-mc GatewayClass。這個 GatewayClass 會佈建跨區域內部應用程式負載平衡器,由 Google Cloud 管理,並啟用內部 VIP,供虛擬私有雲網路內的用戶端存取。只要使用閘道要求這些區域中的位址,即可透過所選區域的前端公開這些閘道。內部 VIP 可以是單一 IP 位址,也可以是多個區域中的 IP 位址,每個區域各有一個 IP 位址 (在閘道中指定)。流量會導向至最接近且健康狀態良好的後端 GKE 叢集,該叢集可處理要求。

事前準備

  1. 使用專案 ID 設定 gcloud 環境,藉此設定專案和殼層:

    export PROJECT_ID="YOUR_PROJECT_ID"
    gcloud config set project ${PROJECT_ID}
    
  2. 在不同地區建立 GKE 叢集。

    這個範例使用兩個叢集,分別是 us-west1 中的 gke-west-1us-east1 中的 gke-east-1。確認已啟用 Gateway API (--gateway-api=standard),且叢集已註冊至機群。

    gcloud container clusters create gke-west-1 \
        --location=us-west1-a \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    
    gcloud container clusters create gke-east-1 \
        --location=us-east1-c \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    

    重新命名背景資訊,方便存取:

    gcloud container clusters get-credentials gke-west-1 \
      --location=us-west1-a \
      --project=${PROJECT_ID}
    
    gcloud container clusters get-credentials gke-east-1 \
      --location=us-east1-c \
      --project=${PROJECT_ID}
    kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west1
    kubectl config rename-context gke_${PROJECT_ID}_us-east1-c_gke-east-1 gke-east1
    
  3. 啟用多叢集服務 (MCS) 和多叢集 Ingress (MCI/Gateway):

    gcloud container fleet multi-cluster-services enable --project=${PROJECT_ID}
    
    # Set the config membership to one of your clusters (e.g., gke-west-1)
    # This cluster will be the source of truth for multi-cluster Gateway and Route resources.
    gcloud container fleet ingress enable \
        --config-membership=projects/${PROJECT_ID}/locations/us-west1/memberships/gke-west-1 \
        --project=${PROJECT_ID}
    
  4. 設定僅限 Proxy 的子網路。 在 GKE 叢集所在區域和負載平衡器運作區域中,您必須建立 Proxy 專用子網路。跨區域內部應用程式負載平衡器需要將這個子網路的用途設為 GLOBAL_MANAGED_PROXY

    # Proxy-only subnet for us-west1
    gcloud compute networks subnets create us-west1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-west1 \
        --network=default \
        --range=10.129.0.0/23 # Choose an appropriate unused CIDR range
    
    # Proxy-only subnet for us-east1
    gcloud compute networks subnets create us-east1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-east1 \
        --network=default \
        --range=10.130.0.0/23 # Choose an appropriate unused CIDR range
    

    如果您未使用預設網路,請將 default 替換為虛擬私有雲網路的名稱。確認 CIDR 範圍不得重複或重疊。

  5. store 等示範應用程式部署至這兩個叢集。範例 store.yaml 檔案 (來自 gke-networking-recipes) 會建立 store 命名空間和部署作業。

    kubectl apply --context gke-west1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    kubectl apply --context gke-east1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    
  6. 在每個叢集中建立 Kubernetes Service 資源和 ServiceExport 資源,從各個叢集匯出服務,讓機群中的所有叢集都能探索這些服務。 以下範例會從每個叢集匯出一般 store 服務和特定區域服務 (store-west-1store-east-1),全部位於 store 命名空間中。

    適用於「gke-west1」:

    cat << EOF | kubectl apply --context gke-west1 -f -
    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 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-west-1 # Exporting the region-specific service
      namespace: store
    EOF
    

    適用於 gke-east1

    cat << EOF | kubectl apply --context gke-east1 -f -
    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 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-east-1 # Exporting the region-specific service
      namespace: store
    EOF
    
  7. 檢查 ServiceImports: 確認 ServiceImport 資源是在 store 命名空間內的每個叢集中建立。建立這些資源可能需要幾分鐘。bash kubectl get serviceimports --context gke-west1 -n store kubectl get serviceimports --context gke-east1 -n store 您應該會看到列出的 storestore-west-1store-east-1 (或根據傳播的相關項目)。

設定內部多區域閘道

定義參照 gke-l7-cross-regional-internal-managed-mc GatewayClass 的 Gateway 資源。將這個資訊清單套用至指定設定叢集,例如 gke-west-1

您可以使用 spec.addresses 欄位,要求特定區域的臨時 IP 位址,或使用預先分配的靜態 IP 位址。

  1. 如要使用臨時 IP 位址,請將下列 Gateway 資訊清單儲存為 cross-regional-gateway.yaml

    # cross-regional-gateway.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-cross-region-gateway
      namespace: store # Namespace for the Gateway resource
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      # Addresses across regions. Address value is allowed to be empty or matching
      # the region name.
      - type: networking.gke.io/ephemeral-ipv4-address/us-west1
        value: "us-west1"
      - type: networking.gke.io/ephemeral-ipv4-address/us-east1
        value: "us-east1"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute # Only allow HTTPRoute to attach
    

    以下清單定義了先前 YAML 檔案中的部分欄位:

    • metadata.namespace:建立 Gateway 資源的命名空間,例如 store
    • spec.gatewayClassName:GatewayClass 的名稱。必須為 gke-l7-cross-regional-internal-managed-mc
    • spec.listeners.allowedRoutes.kinds:可附加的路徑物件類型,例如 HTTPRoute
    • spec.addresses
      • type: networking.gke.io/ephemeral-ipv4-address/REGION:要求臨時 IP 位址。
      • value:指定地址的區域,例如 "us-west1""us-east1"
  2. 將資訊清單套用至設定叢集,例如 gke-west1

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

將 HTTPRoute 附加至 Gateway

定義 HTTPRoute 資源來管理流量轉送,並將這些資源套用至設定叢集。

  1. 將下列 HTTPRoute 資訊清單儲存為 store-route.yaml

    # store-route.yaml
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-route
      namespace: store
      labels:
        gateway: cross-regional-internal
    spec:
      parentRefs:
      - name: internal-cross-region-gateway
        namespace: store # Namespace where the Gateway is deployed
      hostnames:
      - "store.example.internal" # Hostname clients will use
      rules:
      - matches: # Rule for traffic to /west
        - path:
            type: PathPrefix
            value: /west
        backendRefs:
        - group: net.gke.io # Indicates a multi-cluster ServiceImport
          kind: ServiceImport
          name: store-west-1 # Targets the ServiceImport for the west cluster
          port: 8080
      - matches: # Rule for traffic to /east
        - path:
            type: PathPrefix
            value: /east
        backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-east-1 # Targets the ServiceImport for the east cluster
          port: 8080
      - backendRefs: # Default rule for other paths (e.g., /)
        - group: net.gke.io
          kind: ServiceImport
          name: store # Targets the generic 'store' ServiceImport (any region)
          port: 8080
    

    以下清單定義了先前 YAML 檔案中的部分欄位:

    • spec.parentRefs:將這個路徑附加至 store 命名空間中的 cross-region-gateway
    • spec.hostnames:代表用戶端用來存取服務的主機名稱。
    • spec.rules:定義轉送邏輯。本範例使用路徑型轉送:
      • /west 流量會傳送至 store-west-1 ServiceImport。
      • /east 流量會傳送至 store-east-1 ServiceImport。
      • 所有其他流量 (例如 /) 都會前往一般 store ServiceImport。
    • backendRefs
      • group: net.gke.iokind: ServiceImport 目標多叢集服務。
  2. HTTPRoute 資訊清單套用至設定叢集:

    kubectl apply --context gke-west1 -f store-route.yaml
    

確認閘道和路徑的狀態

  1. 檢查閘道狀態:

    kubectl get gateway cross-region-gateway -n store -o yaml --context gke-west1
    

    尋找 type:Programmedand 狀態為「True」的條件:. You should see IP addresses assigned in thestatus.addressesfield, corresponding to the regions you specified (e.g., one forus-west1and one forus-east1。

  2. 檢查 HTTPRoute 狀態:

    kubectl get httproute store-route -n store -o yaml --context gke-west1
    

    status.parents[].conditions 中尋找含有 type: Accepted (或 ResolvedRefs) 和 status: "True" 的條件。

確認流量

將 IP 位址指派給閘道後,您可以從位於虛擬私有雲網路內,且位於其中一個區域的用戶端 VM,或位於可連線至閘道 IP 位址的區域,測試流量。

  1. 擷取閘道 IP 位址。

    下列指令會嘗試剖析 JSON 輸出內容。您可能需要根據確切的結構調整 jsonpath

    kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".
    

    這項指令的輸出內容應包含 VIP,例如 VIP1_WESTVIP2_EAST

  2. 傳送測試要求: 從虛擬私有雲中的用戶端 VM:

    # Assuming VIP_WEST is an IP in us-west1 and VIP_EAST is an IP in us-east1
    # Traffic to /west should ideally be served by gke-west-1
    curl -H "host: store.example.internal" http://VIP_WEST/west
    curl -H "host: store.example.internal" http://VIP_EAST/west # Still targets store-west-1 due to path
    
    # Traffic to /east should ideally be served by gke-east-1
    curl -H "host: store.example.internal" http://VIP_WEST/east # Still targets store-east-1 due to path
    curl -H "host: store.example.internal" http://VIP_EAST/east
    
    # Traffic to / (default) could be served by either cluster
    curl -H "host: store.example.internal" http://VIP_WEST/
    curl -H "host: store.example.internal" http://VIP_EAST/
    

    回覆應包含來自 store 應用程式的詳細資料,指出哪個後端 Pod 處理了要求,例如 cluster_namezone

使用靜態 IP 位址

您可以改用預先分配的靜態內部 IP 位址,而非臨時 IP 位址。

  1. 在要使用的區域中建立靜態 IP 位址:

    gcloud compute addresses create cross-region-gw-ip-west --region us-west1 --subnet default --project=${PROJECT_ID}
    gcloud compute addresses create cross-region-gw-ip-east --region us-east1 --subnet default --project=${PROJECT_ID}
    

    如果未使用預設子網路,請將 default 替換為要分配 IP 位址的子網路名稱。這些子網路是一般子網路,而非僅限 Proxy 的子網路。

  2. 修改 cross-regional-gateway.yaml 檔案中的 spec.addresses 區段,更新閘道資訊清單:

    # cross-regional-gateway-static-ip.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-cross-region-gateway # Or a new name if deploying alongside
      namespace: store
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      - type: networking.gke.io/named-address-with-region # Use for named static IP
        value: "regions/us-west1/addresses/cross-region-gw-ip-west"
      - type: networking.gke.io/named-address-with-region
        value: "regions/us-west1/addresses/cross-region-gw-ip-east"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    
  3. 套用更新後的 Gateway 資訊清單。

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

非預設子網路的特別注意事項

使用非預設子網路時,請注意下列事項:

  • 相同虛擬私有雲網路:所有使用者建立的資源 (例如靜態 IP 位址、僅限 Proxy 的子網路和 GKE 叢集) 都必須位於相同的虛擬私有雲網路。

  • 位址子網路:為閘道建立靜態 IP 位址時,系統會從指定區域的常規子網路分配位址。

  • 叢集子網路命名:每個區域都必須有一個子網路,名稱與 MCG 設定叢集所在的子網路相同。

    • 舉例來說,如果您的 gke-west-1 設定叢集位於 projects/YOUR_PROJECT/regions/us-west1/subnetworks/my-custom-subnet,則您要求位址的地區也必須有 my-custom-subnet 子網路。如果您要求 us-east1us-centra1 地區的位址,則這些地區也必須存在名為 my-custom-subnet 的子網路。

藍綠部署,透過閘道進行多叢集轉送

gke-l7-global-external-managed-*gke-l7-regional-external-managed-*gke-l7-rilb-* GatewayClass 具有許多進階流量轉送功能,包括流量拆分、標頭比對、標頭操控、流量鏡像等。在本範例中,您將示範如何使用權重式流量分割,明確控管兩個 GKE 叢集之間的流量比例。

本範例將逐步說明服務擁有者如何將應用程式遷移或擴展至新的 GKE 叢集。藍綠部署的目標是透過多個驗證步驟降低風險,確認新叢集運作正常。這個範例將逐步說明部署的四個階段:

  1. 100% - 以標頭為準的 Canary 測試使用 HTTP 標頭路由,只將測試或合成流量傳送至新叢集。
  2. 100% - 鏡像流量: 將鏡像使用者流量傳送至 Canary 叢集。這項測試會將 100% 的使用者流量複製到 Canary 叢集,藉此測試叢集的容量。
  3. 90%-10%將流量分配設為 10%,逐步將新叢集開放給實際流量。
  4. 0%-100%完全轉換至新叢集,如果發現任何錯誤,可選擇切換回舊叢集。

在兩個 GKE 叢集之間進行藍綠流量分割

這個範例與前一個範例類似,差別在於這個範例部署的是內部多叢集閘道。這會部署內部應用程式負載平衡器,只能從 VPC 內部私下存取。您將使用先前步驟中部署的叢集和相同應用程式,但會透過不同的 Gateway 部署。

必要條件

下列範例以「部署外部多叢集閘道」中的部分步驟為基礎。請確認您已完成下列步驟,再繼續進行這個範例:

  1. 啟用多叢集閘道

  2. 部署示範應用程式

    這個範例會使用您已設定的 gke-west-1gke-west-2 叢集。這些叢集位於相同區域,因為 gke-l7-rilb-mc GatewayClass 是區域性的,且僅支援相同區域中的叢集後端。

  3. 在每個叢集上部署所需的 Service 和 ServiceExports。如果您從上一個範例部署了服務和 ServiceExports,則您已部署其中一些項目。

    kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/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/main/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
    

設定僅限 Proxy 的子網路

如果您尚未設定,請為部署內部閘道的每個區域設定僅限 Proxy 的子網路。這個子網路用於為負載平衡器 Proxy 提供內部 IP 位址,且必須設定為 --purpose 設為 REGIONAL_MANAGED_PROXY only。

您必須先建立僅限 Proxy 的子網路,才能建立管理內部應用程式負載平衡器的閘道。您在使用內部應用程式負載平衡器的虛擬私有雲 (VPC) 網路的每個區域,都必須有僅限 Proxy 的子網路。

gcloud compute networks subnets create 指令會建立僅限 Proxy 的子網路。

gcloud compute networks subnets create SUBNET_NAME \
    --purpose=REGIONAL_MANAGED_PROXY \
    --role=ACTIVE \
    --region=REGION \
    --network=VPC_NETWORK_NAME \
    --range=CIDR_RANGE

更改下列內容:

  • SUBNET_NAME:僅限 Proxy 子網路的名稱。
  • REGION:僅限 Proxy 子網路的區域。
  • VPC_NETWORK_NAME:包含子網路的虛擬私有雲網路名稱。
  • CIDR_RANGE:子網路的主要 IP 位址範圍。 您必須使用不超過 /26 的子網路遮罩,使該地區的 Proxy 至少有 64 個 IP 位址可用。建議使用的子網路遮罩為 /23

部署閘道

下列 Gateway 是從 gke-l7-rilb-mc GatewayClass 建立,屬於地區內部 Gateway,只能以相同地區的 GKE 叢集為目標。

  1. 將下列 Gateway 資訊清單套用至設定叢集,在本範例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-http
      namespace: store
    spec:
      gatewayClassName: gke-l7-rilb-mc
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    EOF
    
  2. 確認閘道已成功啟動。您可以使用下列指令,只篩選出這個閘道的事件:

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

    如果輸出內容與下列內容相似,表示 Gateway 部署作業成功:

    LAST SEEN   TYPE     REASON   OBJECT                  MESSAGE
    5m18s       Normal   ADD      gateway/internal-http   store/internal-http
    3m44s       Normal   UPDATE   gateway/internal-http   store/internal-http
    3m9s        Normal   SYNC     gateway/internal-http   SYNC on store/internal-http was a success
    

以標頭為準的初期測試

服務擁有者可透過以標頭為準的 Canary 測試,比對非來自真實使用者的合成測試流量。這樣一來,您就能輕鬆驗證應用程式的基本網路功能是否正常運作,不必直接向使用者公開。

  1. 將下列 HTTPRoute 資訊清單套用至設定叢集,在本範例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
      # Matches for env=canary and sends it to store-west-2 ServiceImport
      - matches:
        - headers:
          - name: env
            value: canary
        backendRefs:
          - group: net.gke.io
            kind: ServiceImport
            name: store-west-2
            port: 8080
      # All other traffic goes to store-west-1 ServiceImport
      - backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-west-1
          port: 8080
    EOF
    

    部署後,這個 HTTPRoute 會設定下列轉送行為:

    • 傳送至 store.example.internal 沒有 env: canary HTTP 標頭的內部要求,會路由至 gke-west-1叢集上的 store Pod
    • 傳送至 store.example.internal with 的內部要求會連同 env: canary HTTP 標頭,一併路由至 gke-west-2 叢集上的 store Pod

    HTTPRoute 可根據 HTTP 標頭將流量轉送至不同叢集

    將流量傳送至 Gateway IP 位址,驗證 HTTPRoute 是否正常運作。

  2. internal-http 擷取內部 IP 位址。

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

    在下列步驟中,將 VIP 替換為您收到的輸出 IP 位址。

  3. 使用 env: canary HTTP 標頭將要求傳送至 Gateway,這會確認流量是否轉送到 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. 將下列 HTTPRoute 資訊清單套用至設定叢集,在本例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
      # Sends all traffic to store-west-1 ServiceImport
      - backendRefs:
        - name: store-west-1
          group: net.gke.io
          kind: ServiceImport
          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
    EOF
    
  2. 使用私人用戶端,將要求傳送至 internal-http Gateway。 使用 /mirror 路徑,以便在後續步驟中,於應用程式記錄中明確識別這項要求。

    curl -H "host: store.example.internal" http://VIP/mirror
    
  3. 輸出內容確認用戶端已收到 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"
    }
    

    這可確認主要叢集正在回應流量。您仍須確認要遷移的叢集是否收到鏡像流量。

  4. 檢查 gke-west-2 叢集上 store Pod 的應用程式記錄。記錄應會確認 Pod 已收到負載平衡器的鏡像流量。

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  5. 這項輸出內容確認 gke-west-2 叢集上的 Pod 也收到相同要求,但對這些要求的回應不會傳回給用戶端。記錄中顯示的 IP 位址是負載平衡器的內部 IP 位址,這些位址會與 Pod 通訊。

    Found 2 pods, using pod/store-5c65bdf74f-vpqbs
    [2023-10-12 21:05:20,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:20] "GET /mirror HTTP/1.1" 200 -
    [2023-10-12 21:05:27,158] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 -
    [2023-10-12 21:05:27,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 -
    

流量拆分

流量分割是推出新程式碼或安全部署至新環境最常見的方法之一。服務擁有者會明確設定要傳送至 Canary 後端的流量百分比,通常是整體流量的一小部分,這樣才能在可接受的風險範圍內,判斷推出作業是否成功。

服務擁有者可以透過少數流量進行流量分割,檢查應用程式的健康狀態和回應。如果所有信號都正常,即可繼續進行全面轉換。

  1. 將下列 HTTPRoute 資訊清單套用至設定叢集,在本範例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
      - backendRefs:
        # 90% of traffic to store-west-1 ServiceImport
        - name: store-west-1
          group: net.gke.io
          kind: ServiceImport
          port: 8080
          weight: 90
        # 10% of traffic to store-west-2 ServiceImport
        - name: store-west-2
          group: net.gke.io
          kind: ServiceImport
          port: 8080
          weight: 10
    EOF
    
  2. 使用私人用戶端,持續向 internal- http Gateway 傳送 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. 將下列 HTTPRoute 資訊清單套用至設定叢集,在本範例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
        - backendRefs:
          # No traffic to the store-west-1 ServiceImport
          - name: store-west-1
            group: net.gke.io
            kind: ServiceImport
            port: 8080
            weight: 0
          # All traffic to the store-west-2 ServiceImport
          - name: store-west-2
            group: net.gke.io
            kind: ServiceImport
            port: 8080
            weight: 100
    EOF
    
  2. 使用私人用戶端,持續向 internal- http Gateway 傳送 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 叢集。

部署以容量為基礎的負載平衡

本節的練習會跨不同區域的兩個 GKE 叢集部署應用程式,示範全域負載平衡和服務容量概念。系統會以各種每秒要求數 (RPS) 層級傳送產生的流量,顯示流量如何在叢集和區域之間進行負載平衡。

下圖顯示您將部署的拓撲,以及流量超出服務容量時,流量如何在叢集和區域之間溢出:

流量從一個叢集溢流至另一個叢集

如要進一步瞭解流量管理,請參閱 GKE 流量管理

準備環境

  1. 按照「啟用多叢集閘道」一文的指示準備環境。

  2. 確認 GatewayClass 資源已安裝在設定叢集上:

    kubectl get gatewayclasses --context=gke-west-1
    

    輸出結果會與下列內容相似:

    NAME                                  CONTROLLER                  ACCEPTED   AGE
    gke-l7-global-external-managed        networking.gke.io/gateway   True       16h
    gke-l7-global-external-managed-mc     networking.gke.io/gateway   True       14h
    gke-l7-gxlb                           networking.gke.io/gateway   True       16h
    gke-l7-gxlb-mc                        networking.gke.io/gateway   True       14h
    gke-l7-regional-external-managed      networking.gke.io/gateway   True       16h
    gke-l7-regional-external-managed-mc   networking.gke.io/gateway   True       14h
    gke-l7-rilb                           networking.gke.io/gateway   True       16h
    gke-l7-rilb-mc                        networking.gke.io/gateway   True       14h
    

部署應用程式

將範例網頁應用程式伺服器部署至這兩個叢集:

kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml

輸出結果會與下列內容相似:

namespace/store created
deployment.apps/store created

部署服務、閘道和 HTTPRoute

  1. 將下列 Service 資訊清單套用至 gke-west-1gke-east-1 叢集:

    cat << EOF | kubectl apply --context gke-west-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    
    cat << EOF | kubectl apply --context gke-east-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    

    服務會加上 max-rate-per-endpoint 註解,並設為每秒 10 個要求。每個叢集有 2 個副本,因此每個叢集中的每個服務都有 20 RPS 的容量。

    如要進一步瞭解如何為服務選擇服務容量等級,請參閱「判斷服務容量」。

  2. 將下列 Gateway 資訊清單套用至設定叢集,在本範例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store
      namespace: traffic-test
    spec:
      gatewayClassName: gke-l7-global-external-managed-mc
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    EOF
    

    這個資訊清單說明外部全域多叢集閘道,會部署具有可公開存取 IP 位址的外部應用程式負載平衡器。

  3. 將下列 HTTPRoute 資訊清單套用至設定叢集,在本範例中為 gke-west-1

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store
      namespace: traffic-test
      labels:
        gateway: store
    spec:
      parentRefs:
      - kind: Gateway
        namespace: traffic-test
        name: store
      rules:
      - backendRefs:
        - name: store
          group: net.gke.io
          kind: ServiceImport
          port: 8080
    EOF
    

    資訊清單說明 HTTPRoute,該 HTTPRoute 會使用路由規則設定 Gateway,將所有流量導向商店 ServiceImport。store ServiceImport 會將兩個叢集中的 store Service Pod 分組,並允許負載平衡器將這些 Pod 視為單一 Service。

    幾分鐘後,您可以檢查 Gateway 的事件,確認是否已完成部署:

    kubectl describe gateway store -n traffic-test --context gke-west-1
    

    輸出結果會與下列內容相似:

    ...
    Status:
      Addresses:
        Type:   IPAddress
        Value:  34.102.159.147
      Conditions:
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has deprecated this condition, do not depend on it.
        Observed Generation:   1
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Accepted
        Status:                True
        Type:                  Accepted
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Programmed
        Status:                True
        Type:                  Programmed
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
        Observed Generation:   1
        Reason:                Ready
        Status:                True
        Type:                  Ready
      Listeners:
        Attached Routes:  1
        Conditions:
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:
          Observed Generation:   1
          Reason:                Programmed
          Status:                True
          Type:                  Programmed
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
          Observed Generation:   1
          Reason:                Ready
          Status:                True
          Type:                  Ready
        Name:                    http
        Supported Kinds:
          Group:  gateway.networking.k8s.io
          Kind:   HTTPRoute
    Events:
      Type    Reason  Age                  From                   Message
      ----    ------  ----                 ----                   -------
      Normal  ADD     12m                  mc-gateway-controller  traffic-test/store
      Normal  SYNC    6m43s                mc-gateway-controller  traffic-test/store
      Normal  UPDATE  5m40s (x4 over 12m)  mc-gateway-controller  traffic-test/store
      Normal  SYNC    118s (x6 over 10m)   mc-gateway-controller  SYNC on traffic-test/store was a success
    

    這項輸出內容顯示閘道已成功部署。閘道部署完成後,可能仍需幾分鐘才會開始傳輸流量。請記下這項輸出內容中的 IP 位址,因為後續步驟會用到。

確認流量

使用 curl 指令測試閘道 IP 位址,確認流量是否傳遞至應用程式:

curl GATEWAY_IP_ADDRESS

輸出結果會與下列內容相似:

{
  "cluster_name": "gke-west-1",
  "host_header": "34.117.182.69",
  "pod_name": "store-54785664b5-mxstv",
  "pod_name_emoji": "👳🏿",
  "project_id": "project",
  "timestamp": "2021-11-01T14:06:38",
  "zone": "us-west1-a"
}

這項輸出內容會顯示 Pod 中繼資料,指出要求服務的區域。

使用負載測試驗證流量

如要確認負載平衡器是否正常運作,可以在 gke-west-1 叢集中部署流量產生器。流量產生器會在不同負載層級產生流量,以展示負載平衡器的容量和溢位功能。以下步驟會示範三種負載等級:

  • 10 RPS,低於商店服務的容量 (位於 gke-west-1 中)。
  • 30 RPS,超過 gke-west-1 商店服務的容量,導致流量溢出至 gke-east-1
  • 60 RPS,超過兩個叢集內服務的容量。

設定資訊主頁

  1. 取得 Gateway 的基礎 URLmap 名稱:

    kubectl get gateway store -n traffic-test --context=gke-west-1 -o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
    

    輸出結果會與下列內容相似:

    /projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-traffic-test-store-armvfyupay1t
    
  2. 前往 Google Cloud 控制台的「指標探索器」頁面。

    前往「Metrics Explorer」頁面

  3. 在「選取指標」下方,按一下「代碼:MQL」

  4. 輸入下列查詢,觀察兩個叢集中商店服務的流量指標:

    fetch https_lb_rule
    | metric 'loadbalancing.googleapis.com/https/backend_request_count'
    | filter (resource.url_map_name == 'GATEWAY_URL_MAP')
    | align rate(1m)
    | every 1m
    | group_by [resource.backend_scope],
        [value_backend_request_count_aggregate:
            aggregate(value.backend_request_count)]
    

    GATEWAY_URL_MAP 替換為上一步的 URLmap 名稱。

  5. 按一下 [Run query] (執行查詢)。在下一節中部署負載產生器後,請等待至少 5 分鐘,圖表才會顯示指標。

以每秒 10 個要求的速度進行測試

  1. 將 Pod 部署至 gke-west-1 叢集:

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 10'
    

    GATEWAY_IP_ADDRESS 替換為上一步的閘道 IP 位址。

    輸出內容會與下列內容相似,表示流量產生器正在傳送流量:

    If you don't see a command prompt, try pressing enter.
    

    負載產生器會持續將 10 RPS 傳送至閘道。即使流量來自 Google Cloud 區域內部,負載平衡器仍會將其視為來自美國西岸的用戶端流量。為模擬真實的用戶端多樣性,負載產生器會將每個 HTTP 要求做為新的 TCP 連線傳送,也就是說,流量會更平均地分配到後端 Pod。

    產生器最多需要 5 分鐘,才能為資訊主頁產生流量。

  2. 查看 Metrics Explorer 資訊主頁。系統會顯示兩條線,指出負載平衡至各叢集的流量:

    圖表:顯示負載平衡至叢集的流量

    您應該會看到 us-west1-a 接收到大約 10 RPS 的流量,而 us-east1-b 則未接收到任何流量。由於流量產生器是在 us-west1 中執行,所有流量都會傳送至 gke-west-1 叢集中的服務。

  3. 使用 Ctrl+C 停止負載產生器,然後刪除 Pod:

    kubectl delete pod loadgen --context gke-west-1
    

以 30 RPS 進行測試

  1. 再次部署負載產生器,但這次設定為傳送 30 RPS:

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 30'
    

    產生器最多需要 5 分鐘,才能為資訊主頁產生流量。

  2. 查看 Cloud Ops 資訊主頁。

    圖表:流量溢出至 gke-east-1

    您應該會看到大約有 20 個 RPS 傳送至 us-west1-a,10 個 RPS 傳送至 us-east1-b。這表示 gke-west-1 中的服務已充分利用,且流量溢出 10 RPS 至 gke-east-1 中的服務。

  3. 使用 Ctrl+C 停止負載產生器,然後刪除 Pod:

    kubectl delete pod loadgen --context gke-west-1
    

以 60 RPS 進行測試

  1. 部署設定為傳送 60 RPS 的負載產生器:

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 60'
    
  2. 等待 5 分鐘,然後查看 Cloud Ops 資訊主頁。現在應該會顯示兩個叢集都收到大約 30 RPS。由於全球所有服務都過度使用,因此不會有流量溢出,服務會吸收所有可吸收的流量。

    圖表:服務過度使用

  3. 使用 Ctrl+C 停止負載產生器,然後刪除 Pod:

    kubectl delete pod loadgen --context gke-west-1
    

清除所用資源

完成本頁的練習後,請按照下列步驟移除資源,以免您的帳戶產生不必要的費用:

  1. 刪除叢集

  2. 如果叢集不需要註冊其他用途,請取消註冊機群叢集

  3. 停用 multiclusterservicediscovery 功能:

    gcloud container fleet multi-cluster-services disable
    
  4. 停用多叢集 Ingress:

    gcloud container fleet ingress disable
    
  5. 停用 API:

    gcloud services disable \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        --project=PROJECT_ID
    

使用共用虛擬私有雲的多叢集閘道

多叢集閘道也可以部署在共用虛擬私有雲環境中,並視用途採用不同拓撲。

下表說明共用 VPC 環境中支援的多叢集閘道拓撲:

情境 機群主專案 設定叢集 工作負載叢集
1 共用虛擬私有雲主專案 共用虛擬私有雲主專案 共用虛擬私有雲主專案
2 共用虛擬私有雲服務專案 共用虛擬私有雲服務專案
(與車隊服務專案相同)
共用虛擬私有雲服務專案
(與車隊服務專案相同)

如要在共用虛擬私有雲環境中建立多叢集閘道,請按照下列步驟操作:

  1. 按照步驟使用共用虛擬私有雲設定多叢集服務

  2. 建立服務並匯出至設定叢集

  3. 如果您打算使用多叢集內部閘道,請建立僅限 Proxy 的子網路

  4. 建立多叢集外部內部 Gateway 和 HTTPRoutes

完成上述步驟後,即可根據拓撲驗證部署作業。

疑難排解

內部閘道的 Proxy 專用子網路不存在

如果內部閘道上顯示下列事件,表示該區域沒有僅限 Proxy 的子網路。如要解決這個問題,請部署僅限 Proxy 的子網路。

generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.

沒有健康的上游

症狀:

建立閘道但無法存取後端服務時 (503 回應碼),可能會發生下列問題:

no healthy upstream

原因:

這則錯誤訊息表示健康狀態檢查探測器找不到健康的後端服務。後端服務可能運作正常,但您可能需要自訂健康狀態檢查。

解決方法:

如要解決這個問題,請使用 HealthCheckPolicy,根據應用程式的需求自訂健康狀態檢查 (例如 /health)。

後續步驟