部署多叢集閘道,根據容量進行負載平衡

本文將引導您在不同區域的兩個 GKE 叢集部署範例應用程式,並說明多叢集閘道如何在流量超出服務容量限制時,智慧地轉送流量。

容量型負載平衡是多叢集閘道的功能,可協助您建構高度可靠且具備容錯能力的應用程式。定義服務容量可避免服務超載,確保使用者享有穩定一致的體驗。當某個叢集中的服務達到容量上限時,負載平衡器會自動將流量重新導向至另一個有可用容量的叢集。如要進一步瞭解流量管理,請參閱「GKE 流量管理」。

在本教學課程中,您將使用範例 store 應用程式模擬實際情況,也就是線上購物服務由不同團隊擁有及營運,並部署在共用 GKE 叢集的機群中。

事前準備

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

  1. 部署 GKE 叢集。

  2. 將叢集註冊至機群 (如果尚未註冊)。

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

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

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

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

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

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

準備環境

  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/v1
    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/v1
    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 指令測試 Gateway 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 個要求的速度進行測試

  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
    

疑難排解

沒有健康的上游

症狀:

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

no healthy upstream

原因:

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

解決方法:

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

後續步驟