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

本文說明如何使用以健康狀態檢查為基礎的負載平衡,在 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 以上版本。只有 1.35.0-gke.1403000 以上版本的 GKE 才支援選取備份 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 類別建立 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"

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

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

如要進一步瞭解接聽器使用情形,請參閱「建立 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:識別接收來自已定義永久 IP 位址流量的主要作用中 Pod。這個欄位會使用標籤,比對與 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

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

    spec.template.spec 下方,將以下內容新增至 Deployment 或 StatefulSet YAML 規格:

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

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

    spec.template.spec 下方,將以下內容新增至 Deployment 或 StatefulSet YAML 規格:

    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 的登錄檔,這些 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:要查看的端點類型,可以是 activebackup
  • 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,排程至相同節點。換句話說,同一個節點上同時有符合作用中和備份 podSelector 物件的 Pod。

解決方法

確認作用中和備份 Pod 位於不同節點。更新 GKEIPRoute 設定,並調整 podSelectorbackupPodSelector 標籤,確保同一節點上的兩個 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,但該 Pod 並非處於 READY 狀態,則該 Pod 無法提供流量,也不會被選取。

解決方法

  • 檢查標籤:確認 GKEIPRoute 物件 podSelector 欄位中的標籤,與您套用至目標 Pod 的標籤相符。
  • 確認 Pod 是否存在:確認具有正確標籤的 Pod 確實存在於 Gateway 的 Listeners 指定的 GKEIPRoute 物件命名空間中。如果 reactionMode == Exists 為空,請檢查 Pod 是否已指派給節點 (檢查 pod.Spec.nodeName 欄位)。
  • 確認 Pod 完備性:如果 reactionMode == ReadyCondition,請檢查 Pod 狀態是否為 READY。使用下列指令,確認 Pod 處於 Ready 狀態:

    kubectl get pods -n NAMESPACE
    

    系統不會選取其他狀態的 Pod (例如 PendingError)。

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

症狀

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

可能原因

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

解決方法

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

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

請在這些情況下尋找錯誤訊息,協助排解問題。

後續步驟