設定以健康狀態檢查為準的負載平衡

本文說明如何使用以健康狀態檢查為基礎的負載平衡,在 Google Kubernetes Engine (GKE) 中實作永久 IP 位址的高可用性。雖然標準永久 IP 設定會將單一永久 IP 位址對應至單一 Pod,但透過健康狀態檢查型負載平衡,您可以將一或多個永久 IP 位址的流量分配至健康狀態良好的 Pod 集區。

如要宣告特定永久 IP 位址,並找出接收流量的 Pod,請建立 GKEIPRoute 自訂資源。透過整合 GKEIPRoute 資源與區域健康狀態檢查,GKE 可在網路層監控工作負載,並只將流量轉送至準備好接收流量的 Pod。您也可以使用 GKEIPRoute 物件,指定選用的備份 Pod。 只有在所有主要運作中 Pod 都未通過健康狀態檢查時,GKE 才會將流量轉送至這些待命 Pod。

需求條件和限制

  • 如要使用以健康狀態檢查為準的負載平衡,叢集必須使用 GKE 1.32.3-gke.1440000 以上版本。GKE 僅支援在 1.35.0-gke.1403000 以上版本選取備份 Pod。
  • 叢集必須啟用 GKE Dataplane V2 和 Gateway API。
  • 單一 GKEIPRoute 物件僅支援每個節點一個相符的 Pod。如果節點上的多個 Pod 符合 GKEIPRoute 的 Pod 選取器,GKE 會選擇該節點上最近建立的 Pod。欄位,確保 Pod 分配正確。
  • 建立 GKEIPRoute 物件後,就無法修改 Gateway 類別。
  • 以健康狀態檢查為基礎的負載平衡,僅支援從工作負載外部啟動的流量。不支援從工作負載內啟動的流量傳輸至永久 IP 位址。

事前準備

開始之前,請確認您已執行下列工作:

  • 啟用 Google Kubernetes Engine API。
  • 啟用 Google Kubernetes Engine API
  • 如要使用 Google Cloud CLI 執行這項工作,請安裝並初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行 gcloud components update 指令,取得最新版本。較舊的 gcloud CLI 版本可能不支援執行本文中的指令。

實作以健康狀態檢查為基礎的負載平衡

本節將摘要說明根據健康狀態檢查實作負載平衡的工作流程:

  1. 建立區域性健康狀態檢查:定義 GKE 用來監控 Pod 狀態的參數。這個物件會告知網路層哪些端點正常運作,且有資格接收來自持續性 IP 位址的流量。
  2. 建立叢集:設定已啟用 GKE Dataplane V2 和 Gateway API 的 GKE 叢集。這些元件提供基礎架構,可用於管理永久 IP 路由和以健康狀態檢查為基礎的負載平衡。
  3. 預留 IP 位址:選取並預留與叢集位於相同區域的靜態內部或外部 IP 位址。這個位址是 GKE 會在作用中或備份 Pod 集區中分配的持續性進入點。
  4. 建立閘道:設定閘道物件,管理預留的持續性 IP 位址。GKEIPRoute 物件會為工作負載宣告及使用閘道中的特定 IP 位址。
  5. 建立 GKEIPRoute 物件:定義路由規則,使用標籤選取器將永久 IP 位址對應至一組 Pod。在這個物件中,您可以參照區域健康狀態檢查,並視需要為容錯移轉情境指定備份 Pod。
  6. 查看相符的端點:檢查自動產生的 EndpointSlice,確認 GKE 是否正確識別出作用中和備份 Pod。這個步驟會確認標籤是否符合預期的 Pod,以及網路層是否已準備好轉送流量。

步驟 1:建立區域性健康狀態檢查和防火牆規則

如要建立區域性健康狀態檢查,請按照「建立健康狀態檢查」中的步驟操作。您在此提供的名稱會用於 GKEIPRoute 設定。例如:

gcloud compute health-checks create http reg-lb-hc \
    --region=us-central1 \
    --check-interval=5s \
    --timeout=5s \
    --healthy-threshold=2 \
    --unhealthy-threshold=2

如要允許來自 Google Cloud 的健康狀態檢查探測到達節點,您也必須建立防火牆規則。

步驟 2:建立 GKE 叢集

建立叢集,並啟用 Gateway API 和 GKE Dataplane V2。例如:

gcloud container clusters create cluster-1 \
    --enable-dataplane-v2 \
    --gateway-api=standard \
    --region=us-central1

如果您在虛擬私有雲網路上設定 GKEIPRoute 物件,而該網路與叢集的預設虛擬私有雲網路不同,則必須建立具備多網路功能的 GKE 叢集。詳情請參閱「設定 Pod 的多網路支援功能」。

步驟 3:預留 IP 位址

預留要用於工作負載的 IP 位址。您可以選擇預留 Google 提供的 IP 位址,或使用自己的 IP 位址 (BYOIP)。

步驟 3a:預留 Google 提供的 IP 位址

如要保留外部 IP 位址,請執行下列指令:

gcloud compute addresses create ADDRESS_NAME \
   --region=REGION

更改下列內容:

  • ADDRESS_NAME:要與這個地址建立關聯的名稱。
  • REGION:要保留這個位址的區域。這個區域應與要附加 IP 位址的 Pod 位於相同區域。

    注意:預留 IP 位址時必須指定區域,因為處理持續性 IP 位址流量路徑的轉送規則是區域性的。IP 位址和 GKE 叢集必須位於相同區域,才能正確轉送。

如要保留內部 IP 位址,請執行下列指令:

gcloud compute addresses create ADDRESS_NAME \
    --region REGION
    --subnet SUBNETWORK \
    --addresses IP_ADDRESS

更改下列內容:

  • ADDRESS_NAME:要保留的一或多個地址名稱。如有數個地址,請以空格分隔,並以清單形式指定所有地址。例如:example-address-1 example-address-2 example-address-3。
  • REGION:這項要求適用的區域。
  • SUBNETWORK:這個內部 IPv4 位址的子網路。
  • IP_ADDRESS:所選子網路主要 IP 位址範圍中未使用的內部 IP 位址。

為確保流量在私人網路中正確轉送,內部 IP 位址必須屬於叢集的預設子網路或其他網路子網路。

如要進一步瞭解外部和內部 IP 位址,或查看如何使用 Google Cloud 控制台預留位址,請參閱「預留靜態外部 IP 位址」和「預留靜態內部 IP 位址」。

步驟 3b:自備 IP 位址 (BYOIP)

您可以自備 IP 位址 (BYOIP),不必依賴 Google 提供的 IP 位址。如果您需要應用程式的特定 IP 位址,或是要將現有系統移至 Google Cloud,BYOIP 就很實用。如要使用 BYOIP,Google 會驗證您是否擁有 IP 位址範圍,並在 IP 位址匯入 Google Cloud後,將這些位址指派為 GKE Pod 的 IP 位址。詳情請參閱「使用自己的 IP 位址」。

步驟 4:建立閘道物件

您可以使用下列任一 Gateway 類別建立 Gateway,這些類別僅支援 L3 網路類型:

  • gke-passthrough-lb-external-managed 或
  • gke-passthrough-lb-internal-managed.

以下範例定義的閘道會管理外部 IP 位址集區:

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: lb-gateway
spec:
  gatewayClassName: gke-passthrough-lb-external-managed

  listeners:
    - name: default
      port: 443
      protocol: none
      allowedRoutes:
        namespaces:
          from: All

  addresses:
    - value: "34.123.10.1/32"
      type: "gke.networking.io/cidr"
    - value: "34.123.10.2/32"
      type: "gke.networking.io/cidr"

在上述範例中,請注意下列欄位:

  • 地址:列出特定閘道管理權限的所有 IP 位址範圍。
  • listeners:識別 GKEIPRoute 物件可從哪些命名空間參照這個閘道。

如要進一步瞭解接聽程式的使用情形,請參閱「建立 Gateway 物件」。

步驟 5:建立 GKEIPRoute 物件,並設定負載平衡和健康狀態檢查

建立 GKEIPRoute 物件,定義主要和備份 Pod 選取器,並連結在步驟 1 建立的健康狀態檢查。

kind: GKEIPRoute
apiVersion: networking.gke.io/v1
metadata:
  namespace: default
  name: my-ip-route
spec:
  parentRefs:
  - name: lb-gateway
  addresses:
  - value: "34.123.10.1/32"
    type: "gke.networking.io/cidr"
  - value: "34.123.10.2/32"
    type: "gke.networking.io/cidr"
  network: default
  podSelector:
    matchLabels:
      component: activePodSelector

  loadBalancing:
    healthCheckName: "reg-lb-hc"
    backupPodSelector:
      namespaceSelector:
        matchLabels:
          environment: test
          dc: us-central
      podSelector:
        matchLabels:
          component: backupPodSelector
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: proxy-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: proxy
  template:
    metadata:
      # annotations:  <- Include these lines if the pods are multi-nic pods
      #   networking.gke.io/default-interface: 'eth0'
      #   networking.gke.io/interfaces: '[{"interfaceName":"eth0","network":"default"}, {"interfaceName":"eth1","network":"blue-network"}]'
      labels:
        component: proxy
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0

注意事項:

  • podSelector:識別主要運作中的 Pod,這些 Pod 會接收來自定義的永久 IP 位址的流量。這個欄位會使用標籤,比對與 GKEIPRoute 資源位於相同命名空間的 Pod。GKE 會將流量分配給符合這個選取器的所有健康 Pod。如果多個相符的 Pod 位於同一節點,GKE 只會選取最近建立的 Pod 接收流量。這裡定義的標籤不得與 backupPodSelector 欄位中的標籤重疊。這個欄位可以變更。
  • backupPodSelector:定義待命 Pod,只有在符合 podSelector 物件的所有主要 Pod 未通過健康狀態檢查時,才會接收流量。這個選取器包含下列項目:
    • namespaceSelector:決定 GKE 要搜尋哪些命名空間,才能找到這些備份 Pod。您可以使用標籤選取器,將搜尋範圍限制在特定命名空間。如果省略或留空這個欄位,GKE 會在叢集的所有命名空間中尋找備份 Pod。
    • podSelector:根據備份 Pod 的標籤比對。這些標籤必須與主要 podSelector 物件中使用的標籤不同。

如要進一步瞭解這個資訊清單中的其他欄位,請參閱「建立 GKEIPRoute 物件」。

步驟 6:在 Pod 內使用指派的 IP 位址

使用 GKEIPRoute 物件將 IP 位址指派給 GKE Pod 時,應用程式不會自動使用這些 IP 位址。IP 位址會在網路轉送層級處理,但 Pod 的預設設定不會知道這些位址。您必須設定 Pod 規格,才能辨識及使用 Pod 內的位址。如要達成這個目標,Pod 必須具備權限。

你可以使用下列任一選項設定 Pod 規格:

  • 修改 net.ipv4.ip_nonlocal_bind sysctl

    您可以修改系統設定,允許應用程式使用未直接指派給其介面的 IP 位址,方法是在 Pod securityContext 中設定 net.ipv4.ip_nonlocal_bind sysctl。如果應用程式可以繫結至介面上沒有的 IP 位址,這個選項就很有用。

    在 Deployment 或 StatefulSet YAML 規格的 spec.template.spec 下方,加入下列內容:

    securityContext:
      sysctls:
      - name: net.ipv4.ip_nonlocal_bind
        value: "1"
    
  • 將指派的 IP 位址新增至 Pod 介面

    您可以使用 init 容器,手動將 GKEIPRoute 物件聲明的 IP 位址新增至其中一個 Pod 介面。這會讓 Pod 看到 IP 位址,彷彿是直接指派的位址。這需要 NET_ADMIN 功能。

    在 Deployment 或 StatefulSet YAML 規格的 spec.template.spec 下方,加入下列內容:

    initContainers:
    - name: configure-ips
      image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
      command: ['sh', '-c', 'ip address add ASSIGNED_IP/32 dev eth0']
      securityContext:
        capabilities:
          add:
          - NET_ADMIN
    

    將 ASSIGNED_IP 替換為指派給 GKEIPRoute 物件的其中一個 IP 位址。

  • 原始通訊端:如需進一步控管,應用程式可以直接與網路堆疊互動 (進階)。

  • 使用者空間 IP 位址堆疊:在特殊情況下,Pod 內可能會執行獨立應用程式來管理 IP 位址 (非常進階)。

步驟 7:為指派的 IP 位址啟用 ARP (僅限預設網路)

如要產生有效的位址解析協定 (ARP) 要求和回應,並使用預設網路上 GKEIPRoute 物件指派的 IP 位址,與 Pod 建立新連線,您必須設定 arp_announce 變數。

如要設定 arp_announce 變數,請在 Pod 上執行下列指令:

echo "2" > /proc/sys/net/ipv4/conf/eth0/arp_announce

其中 arp_announce 變數會控管 ARP 宣告的處理方式。 設為「2」可確保系統針對永久 IP 位址發出 ARP 公告,讓網路上的其他裝置得知新的關聯。

步驟 8:查看相符的端點

為管理流量分配,GKE 會為每個 GKEIPRoute 物件建立 EndpointSlice。這些切片會做為所有 Pod 的登錄檔,指定為該特定路徑的轉送目的地。

GKE 會為作用中和備份端點產生個別的 EndpointSlice。系統會根據工作負載,自動調整 EndpointSlice 的數量。雖然單一 EndpointSlice 最多支援 1,000 個端點,但如果相符的 Pod 數量超過這項限制,GKE 會建立額外的切片。

如要查看特定 GKEIPRoute 物件的所有 EndpointSlice,請執行下列指令:

kubectl get endpointslices --all-namespaces -l \
  networking.gke.io/gkeiproute-name=GKEIPROUTE_NAME,\
  networking.gke.io/gkeiproute-namespace=GKEIPROUTE_NAMESPACE

更改下列內容:

  • GKEIPROUTE_NAME:GKEIPRoute 資訊清單的名稱。
  • GKEIPROUTE_NAMESPACE:GKEIPRoute 資訊清單的命名空間。

以下輸出內容顯示 EndpointSlice 的範例:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
 name: {gkeiproute_name-truncated}-{gkeiproute_namespace-truncated}-backup-{unique_hash}
 namespace: {gkeiproute_namespace}
 labels:
  endpointslice.kubernetes.io/managed-by: gkeiproute-controller
  networking.gke.io/gkeiproute-name: {gkeiproute_name}
  networking.gke.io/gkeiproute-namespace: {gkeiproute_namespace}
  networking.gke.io/pip-es-role: backup
 ownerReferences:
  - kind: GKEIPRoute
    name: {gkeiproute_name}
    apiVersion: networking.gke.io/v1
    uid: {uid}
    controller: true
addressType: IPv4
endpoints:
 - addresses:
     - "{pod_ip_address}"
   targetRef:
     Name: {pod_name}
   nodeName: {node_name}

如要查看有效或備份端點的特定 EndpointSlice,請使用 pip-eps-role 標籤篩選結果。例如:

kubectl get endpointslices --all-namespaces -l \
   networking.gke.io/pip-eps-role=ROLE \
  networking.gke.io/gkeiproute-name=GKEIPROUTE_NAME,

更改下列內容:

  • ROLE:要查看的端點類型,可以是 active 或 backup。
  • GKEIPROUTE_NAME:特定 GKEIPRoute 物件的名稱。

排解以健康狀態檢查為基礎的負載平衡問題

本節說明如何解決與健康狀態檢查負載平衡相關的問題。

部分有效 Pod 狀況不佳,但備份 Pod 未接收流量

症狀

GKEIPRoute 狀態會顯示 Ready,表示相符 Pod 的 IP 位址設定已完成。健康狀態檢查或其他診斷結果顯示,部分運作中的 Pod 健康狀態不良。不過,備份 Pod 不會接收流量。

原因

備份 Pod 不會接收流量,直到所有有效 Pod 都不正常為止。在此之前,所有流量都會分配給其餘健康狀態良好的有效 Pod。

解析度

如有必要,請更新 podSelector 欄位標籤,確保這些標籤不再與任何有效的 Pod 相符。GKE 會自動將流量導向後端群組。

已設定 GKEIPRoute,但並非所有 Pod 都收到流量

症狀

GKEIPRoute 狀態顯示 Ready,表示相符 Pod 的 IP 位址設定已完成,但部分相符 Pod 未收到流量。

原因

未接收流量的 Pod 可能健康狀態不佳,或未正確回應健康狀態檢查。請注意,如果所有相符的 Pod 都不健康,GKE 會將流量分配給所有 Pod,無論其健康狀態為何。

解析度

  • 確認 Pod 運作正常:使用 Google Cloud CLI 或Google Cloud 控制台,確認 Pod 能正確回應健康狀態檢查。
  • 視需要進一步調查:如果 Pod 處於不健康的狀態,請確認您已正確為健康狀態檢查設定防火牆,且 Pod 正在回應。

負載平衡器設定無效錯誤

本節說明如何排解 GKEIPRoute 狀態錯誤。

Backup pod and active pod are on the same node

症狀

GKEIPRoute 狀態會回報下列錯誤:

invalid LB configuration: Backup pod %s and active pod %s are on the same node %s. Active and backup pods must reside on different nodes.

原因

符合相同 GKEIPRoute 物件的作用中 Pod 和備份 Pod 會排定在同一個節點上。換句話說,在同一個節點上,有 Pod 同時符合使用中和備份 podSelector 物件。

解析度

確認主要和備份 Pod 位於不同節點。更新 GKEIPRoute 設定,並調整 podSelector 或 backupPodSelector 標籤,確保同一節點上的兩個 Pod 不會比對到相同的 GKEIPRoute 物件。

Pod cannot be selected as both an active and a backup pod

症狀

GKEIPRoute 狀態會回報下列錯誤:

invalid LB configuration: pod %s cannot be selected as both an active and a backup pod. Active and backup pod sets must be mutually exclusive

原因

一或多個 Pod 與 podSelector (有效) 欄位和 backupPodSelector (待命) 欄位的標籤選取器相符。GKE 要求這兩個群組必須互斥。單一 Pod 無法做為自己的備份。

解決方法

請確認主要和備用 Pod 都是獨一無二的。修改 GKEIPRoute 資訊清單中的 podSelector 欄位或 backupPodSelector 欄位,使用更具體或不同的標籤鍵和值。

「NoPodsFound」狀態

症狀

GKEIPRoute 資訊清單會顯示 NoPodsFound 狀態,表示命名空間中沒有標籤相符的 Pod。

可能原因

  • 標籤不正確:您打算使用已設定 IP 位址的 Pod 可能有錯誤的標籤,或完全沒有標籤。
  • 沒有 Pod:如果 reactionMode == Exists,請檢查 Pod 是否已指派給節點 (檢查 pod.Spec.nodeName 欄位)。GKEIPRoute 的命名空間中,可能沒有任何 Pod 與選取器相符。
  • Pod 未就緒:如果顯示 reactionMode == ReadyCondition,請檢查 Pod 狀態是否為 READY。如果相符的 Pod 存在,但並非處於 READY 狀態,則該 Pod 無法提供流量,也不會獲選。

解決方法

  • 檢查標籤:確認 GKEIPRoute 物件的 podSelector 欄位中的標籤,與您套用至目標 Pod 的標籤相符。
  • 確認 Pod 是否存在:確認 GKEIPRoute 物件的命名空間中,確實存在具有正確標籤的 Pod,且該命名空間是由閘道的事件監聽器指定。如果是 reactionMode == Exists,請檢查 pod.Spec.nodeName 欄位,確認 Pod 是否已指派給節點。
  • 確認 Pod 是否已準備就緒:如果顯示 reactionMode == ReadyCondition,請檢查 Pod 狀態是否為 READY。使用下列指令,確認 Pod 處於 Ready 狀態:

    kubectl get pods -n NAMESPACE
    

    其他狀態的 Pod (例如 Pending、Error) 不會選取。

找到相符的 Pod,且 GKEIPRoute IP 位址程式設計正在進行時,狀態為 Mutated

症狀

GKEIPRoute 狀態顯示 Mutated,表示系統正在為相符的 Pod 設定 IP 位址。

可能原因

設定期間,系統會為設定的 IP 位址設定 GKE 資料路徑和 Google Cloud 資源,因此您會看到 Mutated 狀態。

解決方法

  1. 等待並重試:在大多數情況下,設定程序會在短時間內自動完成。請稍後再查看狀態。成功後,圖示會變更為 Ready。
  2. 進一步調查 (如有必要):如果 Mutated 狀態持續一段時間,可能表示設定有誤。檢查 GKEIPRoute 物件的其他狀態條件:

    • 已接受:指出 GKEIPRoute 設定是否有效。
    • GCPReady:指出 Google Cloud 資源是否已如預期設定。

請在這些條件中尋找錯誤訊息,協助排解問題。

後續步驟