使用 GKE Dataplane V2


本頁說明如何為 Google Kubernetes Engine (GKE) 叢集啟用 GKE Dataplane V2,以及如何排解相關問題。

在 1.22.7-gke.1500 以上版本和 1.23.4-gke.1500 以上版本中,新的 Autopilot 叢集會啟用 GKE Dataplane V2。如果使用 GKE Dataplane V2 時發生問題,請跳到「疑難排解」。

使用 GKE Dataplane V2 建立 GKE 叢集

使用 gcloud CLI 或 GKE API 建立 GKE 1.20.6-gke.700 以上版本的新叢集時,可以啟用 GKE Dataplane V2。使用 GKE 1.17.9 以上版本建立新叢集時,您也可以在預覽中啟用 GKE Dataplane V2

控制台

如要使用 GKE Dataplane V2 建立新叢集,請執行下列工作:

  1. 在 Google Cloud 控制台中,前往「建立 Kubernetes 叢集」頁面。

    前往「建立 Kubernetes 叢集」

  2. 在「Networking」(網路) 區段中,勾選「Enable Dataplane V2」(啟用 Dataplane V2) 核取方塊。選取「啟用 Dataplane V2」時,「啟用 Kubernetes 網路政策」選項會停用,因為 GKE Dataplane V2 內建網路政策強制執行功能。

  3. 點選「建立」

gcloud

如要使用 GKE Dataplane V2 建立新叢集,請執行下列指令:

gcloud container clusters create CLUSTER_NAME \
    --enable-dataplane-v2 \
    --enable-ip-alias \
    --release-channel CHANNEL_NAME \
    --location COMPUTE_LOCATION

更改下列內容:

  • CLUSTER_NAME:新叢集的名稱。
  • CHANNEL_NAME:包含 GKE 1.20.6-gke.700 以上版本的發布管道。如果您不想使用發布版本,也可以使用 --cluster-version 旗標而非 --release-channel,並指定 1.20.6-gke.700 以上版本。
  • COMPUTE_LOCATION:新叢集的 Compute Engine 位置

API

如要使用 GKE Dataplane V2 建立新叢集,請在叢集 create 要求中,指定 networkConfig 物件內的 datapathProvider 欄位

下列 JSON 程式碼片段顯示啟用 GKE Dataplane V2 時所需的設定:

"cluster":{
   "initialClusterVersion":"VERSION",
   "ipAllocationPolicy":{
      "useIpAliases":true
   },
   "networkConfig":{
      "datapathProvider":"ADVANCED_DATAPATH"
   },
   "releaseChannel":{
      "channel":"CHANNEL_NAME"
   }
}

更改下列內容:

  • VERSION:叢集版本,必須為 GKE 1.20.6-gke.700 以上版本。
  • CHANNEL_NAME:包含 GKE 1.20.6-gke.700 以上版本的發布管道

排解 GKE Dataplane V2 問題

本節說明如何調查及解決 GKE Dataplane V2 的問題。

  1. 確認已啟用 GKE Dataplane V2:

    kubectl -n kube-system get pods -l k8s-app=cilium -o wide
    

    如果 GKE Dataplane V2 正在執行,輸出內容會包含前置字元為 anetd- 的 Pod。anetd 是 GKE Dataplane V2 的網路控制器。

  2. 如果問題與服務或網路政策強制執行有關,請檢查 anetd Pod 記錄。在 Cloud Logging 中使用下列記錄選取器:

    resource.type="k8s_container"
    labels."k8s-pod/k8s-app"="cilium"
    resource.labels.cluster_name="CLUSTER_NAME"
    
  3. 如果 Pod 建立作業失敗,請查看 kubelet 記錄檔尋找線索。在 Cloud Logging 中使用下列記錄選取器:

    resource.type="k8s_node"
    log_name=~".*/logs/kubelet"
    resource.labels.cluster_name="CLUSTER_NAME"
    

    CLUSTER_NAME 替換為叢集名稱,或完全移除,即可查看所有叢集的記錄。

  4. 如果 anetd Pod 未執行,請檢查 cilium-config ConfigMap 是否經過修改。請避免變更這個 ConfigMap 中的現有欄位,因為這類變更可能會導致叢集不穩定,並中斷 anetd。只有在 ConfigMap 中新增欄位時,系統才會將其修補回預設狀態。系統不會修補現有欄位的任何變更,因此建議不要變更或自訂 ConfigMap。

已知問題

GKE Dataplane V2 叢集發生與 NodePort 範圍衝突相關的間歇性連線問題

在 GKE Dataplane V2 叢集中,經過偽裝的流量或使用暫時性連接埠時,可能會發生間歇性連線問題。這些問題是因可能與保留的 NodePort 範圍發生連接埠衝突所致,通常發生於下列情況:

  • 自訂 ip-masq-agent如果您使用自訂 ip-masq-agent (2.10 以上版本),且叢集具有 NodePort 或負載平衡器服務,可能會因為與 NodePort 範圍衝突而發生間歇性連線問題。2.10 以上版本會預設在內部實作 ip-masq-agent--random-fully 引數。為減輕這類問題的影響,請在 ip-masq-agent 設定的引數中,明確設定 --random-fully=false (適用於 2.11 以上版本)。如需設定詳細資料,請參閱在標準叢集中設定 IP 偽裝代理程式

  • 暫時性通訊埠範圍重疊:如果 GKE 節點上 net.ipv4.ip_local_port_range 定義的暫時性通訊埠範圍與 NodePort 範圍 (30000-32767) 重疊,也可能引發連線問題。為避免這個問題,請確保這兩個範圍不會重疊。

檢查 ip-masq-agent 設定和暫時性通訊埠範圍設定,確保這些設定不會與 NodePort 範圍衝突。如果遇到間歇性連線問題,請考慮下列可能原因,並據此調整設定。

GKE Dataplane V2 叢集中的 hostPort 連線問題

受影響的 GKE 版本:1.29 以上版本

在採用 GKE Dataplane V2 的叢集中,如果流量以節點的 IP:Port 為目標,且通訊埠是 Pod 上定義的 hostPort,您可能會遇到連線失敗的問題。這些問題主要發生在下列兩種情況:

  • 直通式網路負載平衡器後方的節點 (hostPort):

    hostPort 會將 Pod 繫結至特定節點的連接埠,而直通網路負載平衡器則會在所有節點之間分配流量。使用 hostPort 和直通式網路負載平衡器將 Pod 公開至網際網路時,負載平衡器可能會將流量傳送到 Pod 未執行的節點,導致連線失敗。這是因為 GKE Dataplane V2 有已知限制,直通式網路負載平衡器流量不會穩定轉送至 hostPort Pod。

    解決方法:使用直通式網路負載平衡器公開節點上 Pod 的 hostPort 時,請在 Pod 的 hostIP 欄位中指定網路負載平衡器的內部或外部 IP 位址。

    ports:
    - containerPort: 62000
      hostPort: 62000
      protocol: TCP
      hostIP: 35.232.62.64
    - containerPort: 60000
      hostPort: 60000
      protocol: TCP
      hostIP: 35.232.62.64
      # Assuming 35.232.62.64 is the external IP address of a passthrough Network Load Balancer.
    
  • hostPort 與保留的 NodePort 範圍衝突:

    如果 Pod 的 hostPort 與保留的 NodePort 範圍 (30000-32767) 衝突,Cilium 可能無法將流量轉送至 Pod。在叢集 1.29 以上版本中,我們觀察到這種行為,因為 Cilium 現在會管理 hostPort 功能,取代先前的 Portmap 方法。這是 Cilium 的預期行為,公開說明文件中也有提及。

我們不打算在後續版本中修正這些限制。這些問題的根本原因與 Cilium 的行為有關,且超出 GKE 的直接控管範圍。

建議:建議您遷移至 NodePort 服務,而非 hostPort,以提升可靠性。NodePort 兩項服務提供類似功能。

網路政策的連接埠範圍未生效

如果您在已啟用 GKE Dataplane V2 的叢集上,於網路政策中指定 endPort 欄位,該欄位不會生效。

從 GKE 1.22 開始,您可以使用 Kubernetes Network Policy API 指定要強制執行網路政策的連接埠範圍。這個 API 適用於使用 Calico 網路政策的叢集,但不適用於使用 GKE Dataplane V2 的叢集。

NetworkPolicy 物件寫入 API 伺服器後,您可以讀取這些物件,驗證其行為。如果物件仍包含 endPort 欄位,系統就會強制執行這項功能。如果缺少 endPort 欄位,系統就不會強制執行這項功能。在所有情況下,API 伺服器中儲存的物件都是網路政策的可靠來源。

詳情請參閱 KEP-2079:支援連接埠範圍的網路政策

Pod 顯示 failed to allocate for range 0: no IP addresses available in range set 錯誤訊息

受影響的 GKE 版本:1.22 至 1.25

如果 GKE 叢集執行的節點集區使用 containerd,且已啟用 GKE Dataplane V2,可能會發生 IP 位址洩漏問題,導致節點上的所有 Pod IP 位址耗盡。在受影響節點上排定的 Pod 會顯示類似下列內容的錯誤訊息:

failed to allocate for range 0: no IP addresses available in range set: 10.48.131.1-10.48.131.62

如要進一步瞭解這個問題,請參閱 containerd 問題 #5768

已修正的版本

如要修正這個問題,請升級叢集至下列任一 GKE 版本:

  • 1.22.17-gke.3100 以上版本。
  • 1.23.16-gke.200 以上版本。
  • 1.24.9-gke.3200 以上版本。
  • 1.25.6-gke.200 以上版本。

標準 GKE 叢集的解決方法

如要減緩這個問題,請刪除節點外洩的 Pod IP 位址。

如要刪除外洩的 Pod IP 位址,請取得叢集的驗證憑證,然後執行下列步驟來清理單一節點 (如果知道節點名稱)。

  1. 將下列殼層指令碼儲存到名為 cleanup.sh 的檔案:

    for hash in $(sudo find /var/lib/cni/networks/gke-pod-network -iregex '/var/lib/cni/networks/gke-pod-network/[0-9].*' -exec head -n1 {} \;); do hash="${hash%%[[:space:]]}"; if [ -z $(sudo ctr -n k8s.io c ls | grep $hash | awk '{print $1}') ]; then sudo grep -ilr $hash /var/lib/cni/networks/gke-pod-network; fi; done | sudo xargs -r rm
    
  2. 在叢集節點上執行指令碼:

    gcloud compute ssh --zone "ZONE" --project "PROJECT" NODE_NAME --command "$(cat cleanup.sh)"
    

    NODE_NAME 替換為節點名稱。

您也可以執行這個指令碼的 DaemonSet 版本,在所有節點上同時平行執行:

  1. 將下列資訊清單儲存到名為 cleanup-ips.yaml 的檔案:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: cleanup-ipam-dir
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          name: cleanup-ipam
      template:
        metadata:
          labels:
            name: cleanup-ipam
        spec:
          hostNetwork: true
          securityContext:
            runAsUser: 0
            runAsGroup: 0
          containers:
          - name: cleanup-ipam
            image: gcr.io/gke-networking-test-images/ubuntu-test:2022
            command:
              - /bin/bash
              - -c
              - |
                while true; do
                for hash in $(find /hostipam -iregex '/hostipam/[0-9].*' -mmin +10 -exec head -n1 {} \; ); do
                hash="${hash%%[[:space:]]}"
                if [ -z $(ctr -n k8s.io c ls | grep $hash | awk '{print $1}') ]; then
                grep -ilr $hash /hostipam
                fi
                done | xargs -r rm
                echo "Done cleaning up /var/lib/cni/networks/gke-pod-network at $(date)"
                sleep 120s
                done
            volumeMounts:
            - name: host-ipam
              mountPath: /hostipam
            - name: host-ctr
              mountPath: /run/containerd
          volumes:
          - name: host-ipam
            hostPath:
              path: /var/lib/cni/networks/gke-pod-network
          - name: host-ctr
            hostPath:
              path: /run/containerd
    
  2. 在叢集上執行 Daemonset:

    kubectl apply -f cleanup-ips.yaml
    

    您必須擁有叢集管理員的 kubectl 存取權,才能執行這項指令。

  3. 檢查執行中的 DaemonSet 記錄:

    kubectl -n kube-system logs -l name=cleanup-ipam
    

網路政策因連線追蹤查詢錯誤而捨棄連線

當用戶端 Pod 使用服務或內部直通網路負載平衡器的虛擬 IP 位址連線至自身時,由於資料平面中的 conntrack 查閱作業不正確,回覆封包不會識別為現有連線的一部分。這表示系統對封包強制執行網路政策,但該政策會限制 Pod 的傳入流量,因此不正確。

這個問題的影響取決於服務設定的 Pod 數量。舉例來說,如果服務有 1 個後端 Pod,連線一律會失敗。如果服務有 2 個後端 Pod,連線失敗的機率為 50%。

已修正的版本

如要修正這個問題,請將叢集升級至下列任一 GKE 版本:

  • 1.28.3-gke.1090000 以上版本。

解決方法

如要解決這個問題,請在 Service 資訊清單中將 portcontainerPort 設為相同的值。

髮夾彎連線流程的封包捨棄

當 Pod 使用服務建立與自身的 TCP 連線時 (也就是 Pod 同時是連線的來源和目的地),GKE Dataplane V2 eBPF 連線追蹤會錯誤追蹤連線狀態,導致 conntrack 項目洩漏。

如果連線元組 (通訊協定、來源/目的地 IP 和來源/目的地通訊埠) 遭到洩漏,使用相同連線元組的新連線可能會導致回傳封包遭到捨棄。

已修正的版本

如要修正這個問題,請將叢集升級至下列任一 GKE 版本:

  • 1.28.3-gke.1090000 以上版本
  • 1.27.11-gke.1097000 以上版本

解決方法

請使用下列其中一種解決方法:

  • 針對可能使用 Service 與自身通訊的 Pod 中執行的應用程式,啟用 TCP 重複使用 (保持連線)。這樣就不會發出 TCP FIN 標記,避免洩漏 conntrack 項目。

  • 使用存續時間較短的連線時,請使用 Proxy 負載平衡器 (例如 Gateway) 公開 Pod,藉此公開 Service。這會導致連線要求的目的地設為負載平衡器 IP 位址,防止 GKE Dataplane V2 對迴路 IP 位址執行 SNAT。

升級 GKE 控制層會導致 anetd Pod 死結

如果 GKE 叢集已啟用 GKE Dataplane V2 (進階資料路徑),從 1.27 版升級至 1.28 版時,可能會發生死結情況。由於系統無法終止舊版 Pod 或排定 anetd 等必要元件,工作負載可能會中斷。

原因

叢集升級程序會增加 GKE Dataplane V2 元件的資源需求。這項增加可能會導致資源爭用,進而中斷 Cilium 容器網路介面 (CNI) 外掛程式與 Cilium Daemon 之間的通訊。

問題

您可能會出現下列症狀:

  • anetd Pod 仍處於 Pending 狀態。
  • 工作負載 Pod 卡在 Terminating 狀態。
  • 指出 Cilium 通訊失敗的錯誤,例如 failed to connect to Cilium daemon
  • 清除 Pod 沙箱的網路資源時發生錯誤,例如:

    1rpc error: code = Unknown desc = failed to destroy network for sandbox "[sandbox_id]": plugin type="cilium-cni" failed (delete): unable to connect to Cilium daemon... connection refused
    

解決方法

標準叢集:如要解決問題並排定 anetd Pod,請暫時增加受影響節點的可分配資源。

  1. 如要找出受影響的節點,並檢查其可分配的 CPU 和記憶體,請執行下列指令:

    kubectl get nodes $NODE_NAME -o json | jq '.status.allocatable | {cpu, memory}'
    
  2. 如要暫時增加可分配的 CPU 和記憶體,請執行下列指令:

    kubectl patch
    

Autopilot 叢集:如要解決 Autopilot 叢集的死結問題,請強制刪除受影響的 Pod,藉此釋出資源:

kubectl delete pod POD_NAME -n NAMESPACE --grace-period=0 --force

更改下列內容:

  • POD_NAME:Pod 的名稱。
  • NAMESPACE:Pod 的命名空間。

增加節點上可分配的資源後,當從 GKE 1.27 版升級至 1.28 版完成時,anetd Pod 會在新版上執行。

後續步驟