深色模式
K8s 网络排障:跨节点不通怎么办
摘要:容器网络问题最容易让人无从下手。本文给出一套固定排查顺序:先确认 CNI 与节点互通,再验证 Pod IP 直连、Service 转发、DNS 解析,最后看 NetworkPolicy 与 kube-proxy,并附常见原因对照表。
适用环境
- 可用 K8s 集群,≥2 节点
- 已部署 CNI 插件(Calico / Cilium / Flannel 等)
- 节点可 SSH,有
ping、curl、tcpdump、ip等工具
操作步骤
一、先建立排查顺序
固定按这五层从下往上查,能避免乱试:
- 节点层:节点间 IP 是否互通、CNI 端口是否放行
- Pod IP 层:跨节点 Pod IP 能否直连
- Service 层:ClusterIP 能否连通、Endpoints 是否正确
- DNS 层:Service 名能否解析
- 策略层:NetworkPolicy / 防火墙是否拦截
二、节点层检查
bash
kubectl get nodes -o wide
kubectl get pod -n kube-system -l k8s-app=calico-node -o wide # CNI 是否都 Running
ping -c 2 <另一节点IP>1
2
3
2
3
CNI 常见需要放行的端口:
| CNI | 协议/端口 |
|---|---|
| Calico (BGP) | TCP 179 |
| Calico (IPIP) | IP 协议号 4 |
| Calico (VXLAN) | UDP 4789 |
| Flannel (VXLAN) | UDP 8472 |
| Cilium (VXLAN) | UDP 8472 |
注意
云环境除了主机防火墙,还有安全组。跨节点不通时安全组是最常见的被忽略的一环。
三、Pod IP 层验证
起两个分布在不同节点的测试 Pod:
bash
kubectl run net-a --image=busybox --restart=Never -- sleep 3600
kubectl run net-b --image=busybox --restart=Never -- sleep 3600
kubectl get pod -o wide --field-selector metadata.name=net-a1
2
3
2
3
从 net-a 直连 net-b 的 Pod IP(绕过 Service,验证纯网络):
bash
kubectl exec net-a -- ping -c 3 <net-b的PodIP>1
不通则抓包定位:
bash
# 在 net-b 所在节点抓包
sudo tcpdump -i any -nn icmp and host <net-b的PodIP>1
2
2
四、Service 层验证
bash
kubectl expose pod net-b --port=80 --type=ClusterIP 2>/dev/null || true
kubectl get svc
kubectl get ep
kubectl exec net-a -- wget -qO- --timeout=5 http://<ClusterIP>1
2
3
4
2
3
4
ClusterIP 不通但 Pod IP 通 → 问题在 kube-proxy / iptables:
bash
kubectl -n kube-system get pod -l k8s-app=kube-proxy
sudo iptables -t nat -L KUBE-SERVICES -n | grep <ClusterIP>
sudo iptables-save | grep -c KUBE1
2
3
2
3
IPVS 模式下:
bash
sudo ipvsadm -Ln | grep -A3 <ClusterIP>1
五、DNS 层验证
bash
kubectl exec net-a -- nslookup kubernetes.default
kubectl exec net-a -- cat /etc/resolv.conf
kubectl -n kube-system get pod -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=301
2
3
4
2
3
4
resolv.conf 里的 nameserver 必须是 CoreDNS 的 Service ClusterIP,search 应含 <ns>.svc.cluster.local。
六、NetworkPolicy 拦截
bash
kubectl get networkpolicy -A
kubectl describe netpol <名称> -n <命名空间>1
2
2
建议
排查 NetworkPolicy 最快的办法是临时删除策略再测。若删掉就通,说明策略写得太严,再逐条改回。
七、一次性排查脚本
bash
kubectl run netshoot --rm -it --image=nicolaka/netshoot --restart=Never -- bash
# 容器内可用:ping / curl / dig / traceroute / tcpdump / ss / iperf1
2
2
八、常见现象对照表
| 现象 | 最可能原因 |
|---|---|
| 同节点 Pod 通、跨节点不通 | CNI 端口/安全组未放行,或路由未同步 |
| Pod IP 通、ClusterIP 不通 | kube-proxy 异常或 iptables 规则被清 |
| Service 名解析失败 | CoreDNS 未运行或 resolv.conf 被改 |
| 时通时不通 | readinessProbe 未过 / Endpoints 抖动 / 多副本有一半异常 |
| 全部不通但昨天还好 | NetworkPolicy 新上线,或节点防火墙被重置 |
验证
- [ ] 跨节点两个 Pod 能互相 ping 通 Pod IP
- [ ]
kubectl get ep非空且能 wget 通 ClusterIP - [ ]
nslookup kubernetes.default正常解析 - [ ]
kubectl get networkpolicy -A确认没有意外策略
常见坑
- 只在 Pod 里用域名测,忽略 Pod IP 直连测试:无法区分是网络问题还是 DNS 问题。
- Pod 网段与宿主机网络冲突:如 Pod CIDR 用了
172.17.0.0/16与 docker0 撞车,表现为路由诡异。 - MTU 不匹配:VXLAN 封装后超过物理 MTU 导致大包丢弃,表现为小请求通、大响应卡住,需调小 CNI 的 MTU。
- NodePort 外部不通但集群内通:节点防火墙未放行 NodePort 段。
- 清理测试 Pod 失败:
kubectl run没加--rm会留下垃圾 Pod,记得kubectl delete pod net-a net-b。