使用 GKE Dataplane V2


本页面介绍了如何为 Google Kubernetes Engine (GKE) 集群启用 GKE Dataplane V2 以及如何排查它的相关问题。

新的 Autopilot 集群在 1.22.7-gke.1500 版及更高版本和 1.23.4-gke.1500 版及更高版本中启用了 GKE Dataplane V2。如果您在使用 GKE Dataplane V2 时遇到问题,请跳到问题排查

使用 GKE Dataplane V2 创建 GKE 集群

您可以在创建具有 GKE 1.20.6-gke.700 版及更高版本的新集群时使用 gcloud CLI 或 Kubernetes Engine AP 来启用 GKE Dataplane V2。您还可以在创建具有 GKE 1.17.9 版及更高版本的新集群时启用预览版 GKE Dataplane V2

控制台

如需使用 GKE Dataplane V2 创建新集群,请执行以下任务:

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击 创建

  3. 点击配置以配置标准集群。

  4. 在“网络”部分中,选中启用 Dataplane V2复选框。当您选择“启用 Dataplane V2”时,“启用 Kubernetes 网络政策”选项会停用,因为网络政策强制执行功能内置于 GKE Dataplane V2 中。

  5. 点击创建

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 替换为集群的名称,或将其完全移除以查看所有集群的日志。

已知问题

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 版及更高版本)。如需了解配置详情,请参阅在 Standard 集群中配置 IP 伪装代理

  • 临时端口范围重叠:如果 GKE 节点上的 net.ipv4.ip_local_port_range 定义的临时端口范围与 NodePort 范围 (30000-32767) 重叠,也可能会触发连接问题。为避免出现此问题,请确保这两个范围不重叠。

检查您的 ip-masq-agent 配置和临时端口范围设置,确保它们不会与 NodePort 范围冲突。如果您遇到间歇性连接问题,请考虑以下可能的原因,并相应地调整您的配置。

网络政策端口范围未生效

如果您在已启用 GKE Dataplane V2 的集群的网络政策中指定 endPort 字段,则该字段将不会生效。

从 GKE 1.22 开始,Kubernetes Network Policy API 允许您指定强制执行网络政策的端口范围。具有 Calico 网络政策的集群支持此 API,但具有 GKE Dataplane V2 的集群不支持此 API。

如需验证 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

运行使用 containerd 并启用了 GKE Dataplane V2 的节点池的 GKE 集群可能会遇到 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. 将以下 shell 脚本保存到名为 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 使用 Service 或内部直通式网络负载均衡器的虚拟 IP 地址连接到自身时,由于数据平面中不正确的 conntrack 查找,回复数据包不会被识别为现有连接的一部分。这意味着限制 Pod 入口流量的网络政策未在数据包上正确施行。

此问题的影响取决于为 Service 配置的 Pod 数量。比方说,如果 Service 有 1 个后端 Pod,则连接始终失败。如果 Service 有 2 个后端 Pod,则连接失败几率为 50%。

固定版本

如需解决此问题,请将集群升级到以下某个 GKE 版本:

  • 1.28.3-gke.1090000 或更高版本。

解决方法

要缓解此问题,您可以将 Service 清单中的 portcontainerPort 配置为相同的值。

“发卡”(hairpin) 连接流的数据包丢弃

当 Pod 使用 Service 创建与其自身的 TCP 连接时,Pod 同时是连接的来源和目的地时,GKE Dataplane V2 eBPF 连接跟踪会错误地跟踪连接状态,从而导致 conntrack 条目泄露。

当连接元组(协议、源/目标 IP 和源/目标端口)泄露时,使用同一连接元组的新连接可能会导致返回数据包丢弃。

固定版本

如需解决此问题,请将集群升级到以下某个 GKE 版本:

  • 1.28.3-gke.1090000 或更高版本
  • 1.27.11-gke.1097000 或更高版本

解决方法

请使用下列解决方法之一:

  • 为可能使用 Service 与自己通信的 Pod 中运行的应用启用 TCP 重复使用 (keep-alive)。这可以防止发出 TCP FIN 标志,并避免泄露 conntrack 条目。

  • 使用短期连接时,请使用代理负载均衡器(例如网关)公开 Pod,以公开 Service。这会导致连接请求的目的地设置为负载均衡器 IP 地址,从而阻止 GKE Dataplane V2 对环回 IP 地址执行 SNAT。

后续步骤