Kind 环境下 Flannel IPsec 模式跨节点通信故障排查流程
境信息
| 部署方式 | Docker + Kind |
|---|---|
| K8s 版本 | v1.27.3 |
| CNI | Flannel IPsec 模式 |
| 节点网络 | 172.18.0.0/16(Docker bridge) |
问题现象
同节点 Pod 通信正常,跨节点 Pod 通信卡住超时:
# 同节点访问正常 docker exec flannel-ipsec-control-plane curl -s 10.244.0.4 PodName: Pod-1 | PodIP: eth0 10.244.0.4/24 # 跨节点访问卡住 docker exec flannel-ipsec-control-plane curl -s 10.244.1.7 # 无响应...检查 IPsec 状态,SA 未建立:
docker exec flannel-ipsec-control-plane ip xfrm state # 空排查过程
查看 Flannel 日志
control-plane 节点:
kubectl logs -n kube-system kube-flannel-ds-cd8rf 06[CFG] loaded IKE shared key for: '172.18.0.3' 13[CFG] loaded IKE shared key for: '172.18.0.2' 07[NET] received packet: from 172.18.0.1[500] to 172.18.0.3[500] (720 bytes) 07[IKE] no IKE config found for 172.18.0.3...172.18.0.1, sending NO_PROPOSAL_CHOSENworker 节点:
kubectl logs -n kube-system kube-flannel-ds-gk7pl 11[NET] sending packet: from 172.18.0.2[500] to 172.18.0.3[500] (720 bytes) 04[NET] received packet: from 172.18.0.1[500] to 172.18.0.2[500] (720 bytes) 04[IKE] no IKE config found for 172.18.0.2...172.18.0.1, sending NO_PROPOSAL_CHOSEN发现问题:
IKE 包经过 Docker bridge 时,源 IP 被 SNAT 成了网关地址。
| 预期源 IP | 实际源 IP |
|---|---|
| 172.18.0.2 (worker) | 172.18.0.1 (网关) |
| 172.18.0.3 (control-plane) | 172.18.0.1 (网关) |
检查 iptables NAT 规则
iptables -t nat -L POSTROUTING -n -v Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 706 42360 MASQUERADE 0 -- * !br-822761cba2a3 172.18.0.0/16 0.0.0.0/0 269 19012 MASQUERADE 0 -- * !br-64b0f4dac739 172.18.0.0/16 0.0.0.0/0按规则字面意思,出口不是网桥!br-xxx才触发 MASQUERADE,同网桥转发不应该 NAT。
但问题是:K8s 部署时需要开启bridge-nf-call-iptables = 1,导致网桥转发流量也会经过 iptables,触发了 MASQUERADE。
cat /proc/sys/net/bridge/bridge-nf-call-iptables # 1流量示意:
bridge-nf-call-iptables=1
MASQUERADE
容器A
网桥
iptables
容器B
bridge-nf-call-iptables=0
容器A
网桥
容器B
问题原因
Kind 环境下,K8s 节点本身是 Docker 容器,通过网桥互联。bridge-nf-call-iptables = 1导致同网桥转发的流量也经过 iptables,触发 Docker 的 MASQUERADE 规则,源 IP 被改成网关 IP(172.18.0.1),Flannel IPsec 的 IKE 协商因此失败。
注:这是 Kind 环境特有的问题,kubeadm 部署的物理机/VM 环境不经过 Docker 网桥,不会遇到类似问题。
解决方案
在宿主机添加 iptables 规则,让同网段流量跳过 MASQUERADE:
iptables -t nat -I POSTROUTING -s 172.18.0.0/16 -d 172.18.0.0/16 -j ACCEPT规则说明:
| 参数 | 含义 |
|---|---|
-t nat | 操作 NAT 表 |
-I POSTROUTING | 插入到 POSTROUTING 链最前面(优先级最高) |
-s 172.18.0.0/16 | 匹配源 IP |
-d 172.18.0.0/16 | 匹配目的 IP |
-j ACCEPT | 直接接受,跳过后续规则 |
添加后验证:
iptables -t nat -L POSTROUTING -n -v Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 19 2648 ACCEPT 0 -- * * 172.18.0.0/16 172.18.0.0/16 706 42360 MASQUERADE 0 -- * !br-822761cba2a3 172.18.0.0/16 0.0.0.0/0 269 19012 MASQUERADE 0 -- * !br-64b0f4dac739 172.18.0.0/16 0.0.0.0/0重启 Flannel 触发重新协商:
kubectl rollout restart daemonset -n kube-system kube-flannel-ds验证 SA 已建立:
# docker exec flannel-ipsec-control-plane ip xfrm state src 172.18.0.3 dst 172.18.0.2 proto esp spi 0xc1115682 reqid 11 mode tunnel replay-window 0 flag af-unspec aead rfc4106(gcm(aes)) 0x217a8659909ac029fb600b7cab791ee5b31d3563 128 anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000 src 172.18.0.2 dst 172.18.0.3 proto esp spi 0xc3b69836 reqid 11 mode tunnel replay-window 32 flag af-unspec aead rfc4106(gcm(aes)) 0xfaa2ea9f4bfb893623ce9fc5aac9ae6646913ee7 128 anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000 src 172.18.0.3 dst 172.18.0.2 proto esp spi 0xc9b2e230 reqid 11 mode tunnel replay-window 0 flag af-unspec aead rfc4106(gcm(aes)) 0x93c09105fd818db55e1b2d730fd31ff989fd33c2 128 anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000 src 172.18.0.2 dst 172.18.0.3 proto esp spi 0xc709b48b reqid 11 mode tunnel replay-window 32 flag af-unspec aead rfc4106(gcm(aes)) 0x60697edd7c58b57220c15d3b9d41851a206d4e4e 128 anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000跨节点 Pod 通信测试:
docker exec flannel-ipsec-control-plane curl -s 10.244.1.7 # PodName: Pod-0 | PodIP: eth0 10.244.1.7/24