本页面介绍了如何为 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 或 GKE API 来启用 GKE Dataplane V2。您还可以在创建具有 GKE 1.17.9 版及更高版本的新集群时启用预览版 GKE Dataplane V2
控制台
如需使用 GKE Dataplane V2 创建新集群,请执行以下任务:
在 Google Cloud 控制台中,前往创建一个 Kubernetes 集群页面。
在“网络”部分中,选中启用 Dataplane V2复选框。当您选择“启用 Dataplane V2”时,“启用 Kubernetes 网络政策”选项会停用,因为网络政策强制执行功能内置于 GKE Dataplane V2 中。
点击创建。
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 的问题。
确认已启用 GKE Dataplane V2:
kubectl -n kube-system get pods -l k8s-app=cilium -o wide
如果 GKE Dataplane V2 正在运行,则输出包含前缀为
anetd-
的 Pod。anetd 是 GKE Dataplane V2 的网络控制器。如果问题在于服务或网络政策强制执行方式,请检查
anetd
Pod 日志。在 Cloud Logging 中使用以下日志选择器:resource.type="k8s_container" labels."k8s-pod/k8s-app"="cilium" resource.labels.cluster_name="CLUSTER_NAME"
如果 Pod 创建失败,请检查 kubelet 日志以获取相关线索。在 Cloud Logging 中使用以下日志选择器:
resource.type="k8s_node" log_name=~".*/logs/kubelet" resource.labels.cluster_name="CLUSTER_NAME"
将
CLUSTER_NAME
替换为集群的名称,或将其完全移除以查看所有集群的日志。如果
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 版及更高版本)。如需了解配置详情,请参阅在 Standard 集群中配置 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:端口”且其中的端口是 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
Service(而不是 hostPort
)以提高可靠性。NodePort
Service 提供类似的功能。
网络政策端口范围未生效
如果您在已启用 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 地址,请获取集群的身份验证凭据并执行以下步骤来清理单个节点(如果您知道其名称)。
将以下 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
在集群节点上运行脚本:
gcloud compute ssh --zone "ZONE" --project "PROJECT" NODE_NAME --command "$(cat cleanup.sh)"
将
NODE_NAME
替换为该节点的名称。
您还可以运行此脚本的 DaemonSet 版本以同时在所有节点上并行运行:
将以下清单保存到名为
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
在集群上运行 daemonset:
kubectl apply -f cleanup-ips.yaml
您必须具有集群管理员的 kubectl 访问权限才能运行此命令。
检查正在运行的 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 清单中的 port
和 containerPort
配置为相同的值。
“发卡”(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。
GKE 控制平面升级导致 anetd
Pod 死锁
如果您将启用了 GKE Dataplane V2(高级数据路径)的 GKE 集群从 1.27 版升级到 1.28 版,可能会遇到死锁情况。由于无法终止旧 Pod 或无法调度必要组件(如 anetd
),工作负载可能会遇到中断问题。
原因
集群升级过程会增加对 GKE Dataplane V2 组件的资源要求。这种增加可能会导致资源争用,从而中断 Cilium 容器网络接口 (CNI) 插件与 Cilium 守护程序之间的通信。
表现
您可能会看到以下症状:
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
临时解决方法
Standard 集群:如需解决此问题并允许调度 anetd
Pod,请暂时增加受影响节点上的可分配资源。
如需确定受影响的节点并检查其可分配的 CPU 和内存,请运行以下命令:
kubectl get nodes $NODE_NAME -o json | jq '.status.allocatable | {cpu, memory}'
如需暂时增加可分配的 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 会在较新版本上运行。
后续步骤
- 使用网络政策日志记录功能记录集群网络政策允许或拒绝与 Pod 连接的时间。
- 了解 GKE Dataplane V2 的工作原理。