步骤三:区分同节点和跨节点故障
kubectl get pods -A -o wide
找同节点和跨节点的测试对象,分别测试相同协议和端口:
- 同节点成功、跨节点失败: 优先查节点之间的路由、隧道、防火墙。
- 只有某个目标 Pod 不通: 优先查目标端口、标签和网络策略。
- 某台节点上的 Pod 普遍不通: 优先查该节点的 CNI、路由和网络状态。
- 整个集群访问 Service 异常: 先看 Service、后端和转发组件。
步骤四:检查 NetworkPolicy
先列出策略:
查看目标命名空间的具体策略:
kubectl describe netpol 策略名 -n app-ns
kubectl get netpol -n app-ns -o yaml
重点看四个位置:
podSelector: 策略选中了哪些标签的 Pod。
Ingress: 目标 Pod 允许谁访问、允许哪些端口。
Egress: 源 Pod 能访问哪里、能走哪些端口。
namespaceSelector: 是否允许其他命名空间访问。
例如目标 Pod 带 app=web,策略选中了它,并且配置:
ingress: []
policyTypes:
- Ingress
这表示该策略没有放行任何入站连接。还要看是否存在其他放行策略,因为 Kubernetes NetworkPolicy 的允许规则会合并生效。
判断一条连接能否成功,要同时检查:源 Pod 的出站规则、目标 Pod 的入站规则。
Calico 集群还可能使用自己的策略资源:
kubectl get globalnetworkpolicies.crd.projectcalico.org
kubectl get networkpolicies.crd.projectcalico.org -A
如果集群没有对应 Calico CRD,就跳过这两条。生产环境还可能有安全组、主机防火墙等额外限制。
步骤五:检查 CNI 插件
先确认集群用的网络插件:
kubectl get pods -n kube-system -o wide
Calico 集群可以直接看:
kubectl get pods -n kube-system -l k8s-app=calico-node -o wide
找到故障节点对应的 Calico Pod,再查日志:
kubectl logs -n kube-system calico-node-xxxxx -c calico-node --tail=100
这里把 calico-node-xxxxx 换成实际名称。关注组件反复重启、Felix、路由同步、IP 分配和网卡相关报错。
查看 Calico 地址池和封装模式:
kubectl get ippools.crd.projectcalico.org -o yaml
ipipMode: Always:使用 IPIP 封装。
vxlanMode: Always:使用 VXLAN 封装。
- 都为
Never:查看实际路由或其他数据面配置。
这些字段用于判断网络模式,按现场配置选对应排查方法。
步骤六:跨节点异常时查路由、隧道和防火墙
进入源节点的宿主机,查看访问目标 Pod IP 走哪条路:
IPIP 模式下查看隧道设备:
查看节点防火墙规则:
如果确认使用 IPIP,先在源节点和目标节点对应的物理网卡上抓包,同时发起测试请求:
sudo tcpdump -ni eth0 'ip proto 4' -c 10
eth0 换成实际网卡。IPIP 使用 IP 协议号 4,不是 TCP 4 端口。
| 抓包现象 | 重点排查 |
|---|
| 源节点没有发出 IPIP 流量 | 源节点路由、Calico、隧道配置 |
| 源节点有包,目标节点收不到 | 节点间网络、防火墙、安全策略 |
| 目标节点收到,目标 Pod 仍不通 | 解封装、目标路由、Pod 网络规则 |
VXLAN 模式改查实际 UDP 封装端口,Calico 常用 4789/UDP。抓包和查看规则先定位问题,不要直接清空 iptables 或重启整个网络插件。
步骤七:Pod IP 通,Service IP 不通
先查看 Service:
kubectl get svc -n app-ns
kubectl describe svc web-svc -n app-ns
查看 Service 选中了哪些后端:
kubectl get endpointslice -n app-ns -l kubernetes.io/service-name=web-svc
| 看哪里 | 如何判断 |
|---|
Service selector | 是否匹配后端 Pod 的标签 |
Service port | 客户端访问的 Service 端口是否正确 |
targetPort | 是否指向程序真正监听的端口 |
| EndpointSlice | 是否有预期的后端 Pod IP、端口和就绪状态 |
后端为空: 先查标签、Pod Ready 状态和 EndpointSlice。
后端正确、Pod IP 可通、Service IP 不通: 查 kube-proxy 或实际使用的 Service 转发数据面以及节点网络规则。
步骤八:Service IP 通,域名不通
在带有 DNS 工具的客户端 Pod 内查询服务域名:
nslookup web-svc.app-ns.svc.cluster.local
查看 Pod 采用的 DNS 配置:
上面两条在客户端容器内执行。若容器缺少 nslookup,使用现有诊断 Pod 或经过批准的临时排查容器。
再从控制节点检查 CoreDNS:
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get svc kube-dns -n kube-system
- 域名解析不到 IP:查 CoreDNS、域名拼写、命名空间和 Pod DNS 配置。
- 只有启用限制策略后 DNS 失败:查客户端的 Egress 是否放行 DNS 53 端口。
- 解析结果正确但访问仍失败:回头检查 Service 和实际后端。
步骤九:修复以后怎么确认?
用修复前相同的客户端、目标地址、协议和端口再次测试。
同时确认:Pod 状态正常、实际业务请求恢复、没有新增异常日志。
生产环境修改 NetworkPolicy 时,优先补充需要的放行规则或回退错误变更。删除整条隔离策略可能放开其他不该开放的流量。
03 六类典型生产故障与处理方法
这一章按故障现象 → 怎么查 → 怎么处理组织。第一类包含本次真实复现;其余为通用排查场景和配置示例,不冒充实测结果。
场景一:NetworkPolicy 拦截了正常业务访问(实测)
现象: 两个 Pod 都是 Running;目标 Nginx 在容器内可访问;另一个节点的 Pod 访问目标 IP 超时。
本次测试环境:K8s v1.28.15,Calico v3.26.1。
| 项目 | 实测值 |
|---|
| 客户端 | client,server-84,10.244.250.218 |
| 目标服务 | web(Nginx),server-85,10.244.104.137:80 |
| 命名空间 | pod-net-demo |
| 目标 Pod 标签 | app=web |
先看状态、端口和请求:
kubectl get pods -n pod-net-demo -o wide --show-labels
kubectl exec -n pod-net-demo web -- wget -S --spider localhost
kubectl exec -n pod-net-demo client -- curl -m 5 -I 10.244.104.137
实测: 两个 Pod 正常、Nginx 本地可访问,但客户端返回:
curl: (28) Connection timed out after 5003 milliseconds
command terminated with exit code 28
查看策略:
kubectl get netpol -n pod-net-demo
kubectl describe netpol deny-web -n pod-net-demo
关键输出:
PodSelector: app=web
Allowing ingress traffic:
<none> (Selected pods are isolated for ingress connectivity)
Policy Types: Ingress
原因: deny-web 选中了带 app=web 标签的 Pod,没有配置允许进入的流量规则;实验中也没有其他策略放行该请求。
实验环境直接删除测试策略:
kubectl delete netpol deny-web -n pod-net-demo
kubectl exec -n pod-net-demo client -- curl -m 5 -I 10.244.104.137
实测恢复结果: HTTP/1.1 200 OK。
生产环境推荐补充最小范围的放行规则。例如下面的策略允许同一命名空间带 app=client 标签的 Pod 访问 app=web 的 TCP 80 端口:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-client-to-web
namespace: pod-net-demo
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: client
ports:
- protocol: TCP
port: 80
这是修复配置示例,本次没有实际应用。跨命名空间还要匹配正确的 namespaceSelector;如果源 Pod 有出站隔离,还需同时放行 Egress。
场景二:同节点正常,跨节点访问超时
典型现象: 同节点 Pod 正常访问;跨节点访问超时;网络插件的 Pod 可能仍显示 Running。
排查顺序:
- 对比同节点、跨节点的业务端口测试。
- 查 NetworkPolicy,确认没有针对源或目标的拦截。
- 查 CNI 使用 IPIP、VXLAN 还是纯路由。
- 查源节点到目标 Pod IP 的路由。
- 两侧抓包,确认数据在哪一段丢失。
关键命令:
kubectl get pods -A -o wide
kubectl get netpol -A
kubectl get ippools.crd.projectcalico.org -o yaml
ip route get 目标PodIP
如果是 IPIP,再查 tunl0 和 IP 协议号 4:
ip -d link show tunl0
sudo tcpdump -ni eth0 'ip proto 4' -c 10
处理: 根据路由、抓包结果修复隧道配置、节点间路由或放通相应封装协议。只调整确认有问题的节点或网络规则。
场景三:Service 标签或端口配错
典型现象: 直接访问 Pod IP 正常,访问 Service IP 失败。
先查配置和实际后端:
kubectl describe svc web-svc -n app-ns
kubectl get endpointslice -n app-ns -l kubernetes.io/service-name=web-svc
kubectl get pods -n app-ns --show-labels
例如 Pod 的标签是 app=web,Service 的 selector 却写成 app=nginx,Service 就选不到这些 Pod。另一种常见问题是程序监听 8080,而 Service 的 targetPort 写成 80。
处理: 修正 Service selector 或 targetPort,确认 EndpointSlice 出现正确后端,再测试 Service IP。
场景四:CoreDNS 或 DNS 出站策略导致域名访问失败
典型现象: Service IP 能访问,使用 web-svc.app-ns.svc.cluster.local 却失败。
在有 nslookup 的诊断容器内测试:
nslookup web-svc.app-ns.svc.cluster.local
cat /etc/resolv.conf
从控制节点查看:
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get svc kube-dns -n kube-system
处理: 域名或命名空间写错就修正调用地址;CoreDNS 异常查日志和上游 DNS;NetworkPolicy 限制 Egress 时,按实际 DNS 服务地址放行 UDP/TCP 53。
场景五:容器只监听 127.0.0.1
典型现象: Pod 内访问 localhost 成功;访问 Pod 自己的 IP 失败;其他 Pod 也无法连接。
在目标容器内分别测试:
wget -S --spider localhost:8080
wget -S --spider 10.244.1.20:8080
容器有 ss 时再看监听地址:
处理: 把应用监听地址调整为 0.0.0.0 或实际 Pod 网卡地址,重新部署并验证。注意有些精简镜像没有 ss、wget,可使用诊断容器。
场景六:CNI 或某个节点网络异常
典型现象: 某台节点上的多个 Pod 同时出现网络问题,其他节点正常;可能伴随 Calico 频繁重启、分配 IP 失败或网络接口异常。
先按节点查 Pod 分布:
kubectl get pods -A -o wide
kubectl get pods -n kube-system -o wide
再查故障节点上的 CNI 日志、节点事件和路由:
kubectl describe node 节点名
kubectl logs -n kube-system calico-node-xxxxx -c calico-node --tail=100
ip route
处理: 根据明确报错修复地址池、路由、节点防火墙或 CNI 配置。生产环境调整前确认节点上承载的业务和回退办法。
04 生产排障命令速查表
把命名空间、Pod 名、IP 和端口换成现场值。
| 查什么 | 命令 | 重点看 |
|---|
| 全集群 Pod 分布 | kubectl get pods -A -o wide | IP、NODE、STATUS |
| Pod 标签 | kubectl get pods -n app-ns --show-labels | LABELS |
| Pod 事件 | kubectl describe pod web -n app-ns | Events |
| 应用日志 | kubectl logs web -n app-ns --tail=50 | 启动和异常日志 |
| 容器内 HTTP | kubectl exec -n app-ns web -- wget -S --spider localhost:80 | HTTP 状态 |
| Pod IP HTTP | kubectl exec -n app-ns client -- curl -m 5 -I 10.244.1.20:80 | 成功、拒绝、超时 |
| 网络策略 | kubectl get netpol -A | 哪些命名空间有策略 |
| 策略详情 | kubectl describe netpol 策略名 -n app-ns | selector、Ingress、Egress |
| Calico 状态 | kubectl get pods -n kube-system -l k8s-app=calico-node | READY、RESTARTS |
| Calico 日志 | kubectl logs -n kube-system calico-node-xxxxx -c calico-node --tail=100 | Felix、路由、IP 错误 |
| Calico 网络模式 | kubectl get ippools.crd.projectcalico.org -o yaml | CIDR、IPIP、VXLAN |
| 节点路由 | ip route get 目标PodIP | 出口设备、下一跳 |
| IPIP 隧道 | ip -d link show tunl0 | 隧道设备 |
| IPIP 抓包 | sudo tcpdump -ni eth0 'ip proto 4' -c 10 | 封装流量有无到达 |
| 节点防火墙 | sudo iptables -S | 过滤规则 |
| Service 信息 | kubectl describe svc web-svc -n app-ns | selector、port、targetPort |
| Service 后端 | kubectl get endpointslice -n app-ns -l kubernetes.io/service-name=web-svc | 后端 IP 和端口 |
| CoreDNS | kubectl get pods -n kube-system -l k8s-app=kube-dns | Pod 状态 |
| DNS 配置 | cat /etc/resolv.conf(Pod 内) | nameserver、search |
速记:本地端口 → Pod IP → NetworkPolicy → 跨节点网络;Pod IP 通了,再看 Service 和 DNS。
05 面试应答参考话术
面试问题:两个 Pod 之间无法通信,你怎么排查?
先确认两个 Pod 的状态、IP、所在节点和业务端口,再从源 Pod 测试目标 Pod IP。
如果本地服务正常但 Pod IP 不通,我会检查 NetworkPolicy,包括目标入站和源端出站规则。
如果同节点能通、跨节点不能通,就重点查 CNI、路由、IPIP 或 VXLAN 隧道和节点防火墙。
如果 Pod IP 正常但 Service 不通,查 selector、targetPort 和 EndpointSlice;只有域名不通,再查 CoreDNS。
找到原因后按变更流程修复,用原来的请求验证恢复。
06 面试高频追问与应答预案
Q1:Pod 是 Running,为什么仍然无法访问?
容器在运行,但应用可能没监听正确端口,也可能被网络策略或节点网络拦截。
Q2:为什么优先用 curl 测端口?
HTTP 业务就测 HTTP 端口,结果更接近实际故障;ping 只测 ICMP。
Q3:NetworkPolicy 是谁执行的?
Kubernetes 保存策略配置,Calico 等支持策略的 CNI 组件负责执行。
Q4:Calico 和 Flannel 的主要区别?
两者都能实现 Pod 网络互通;Calico 还支持 NetworkPolicy,基础 Flannel 通常要搭配额外组件才能执行网络策略。
Q5:podSelector: app=web 选中了谁?
选中策略所在命名空间中带 app=web 标签的 Pod,和 Pod 名称无关。
Q6:ingress: [] 是什么意思?
该策略没有放行任何入站连接。实际是否能访问,还要结合其他策略一起判断。
Q7:为什么源 Pod 的 Egress 也要查?
目标允许进入、源端禁止发出,连接一样失败。
Q8:为什么要区分同节点和跨节点?
只有跨节点不通,排查重点就是节点间路由、隧道和防火墙。
Q9:IPIP 和 VXLAN 有什么用?
把 Pod 网络流量封装后传到另一台节点。IPIP 使用 IP 协议号 4,VXLAN 常见 UDP 4789。
Q10:Calico 显示 Running,还会有网络问题吗?
会。继续结合日志、策略、路由和实际抓包定位。
Q11:Pod IP 正常,Service IP 不通查什么?
查 selector、targetPort、EndpointSlice 和 Service 转发规则。
Q12:Service IP 正常,域名不通查什么?
查 CoreDNS、resolv.conf、命名空间和 DNS 出站策略。
Q13:Connection refused 和 Connection timed out 有什么区别?
refused 优先查端口监听和拒绝规则;timed out 优先查策略、路由和丢包。
Q14:生产发现 NetworkPolicy 写错了,怎么处理?
确认实际需要放行的来源和端口,补正确规则或回退错误变更,最后复测业务。
07 Pod 网络只读辅助排查脚本
脚本自动获取源 Pod、目标 Pod、目标 IP、节点和标签,检查两端命名空间的 NetworkPolicy,并测试目标 HTTP 端口;不会修改集群配置。
脚本支持两个 Pod 在不同命名空间,命令格式:
bash pod_net_diag.sh 源命名空间 源Pod 目标命名空间 目标Pod HTTP端口
示例:
bash pod_net_diag.sh pod-net-demo client pod-net-demo web 80
完整脚本:
#!/usr/bin/env bash
# 用法: bash pod_net_diag.sh 源ns 源Pod 目标ns 目标Pod HTTP端口
set -u
if [ "$#" -ne 5 ]; then
echo "用法: bash $0 源ns 源Pod 目标ns 目标Pod HTTP端口" >&2
exit 2
fi
src_ns=$1
src=$2
dst_ns=$3
dst=$4
port=$5
if ! [[ "$port" =~ ^[0-9]+$ ]] || (( 10#$port < 1 || 10#$port > 65535 )); then
echo '端口必须是1到65535之间的数字' >&2
exit 2
fi
command -v kubectl >/dev/null || { echo '找不到kubectl' >&2; exit 1; }
echo '===== 源Pod ====='
kubectl get pod "$src" -n "$src_ns" -o wide --show-labels || exit 1
echo '===== 目标Pod ====='
kubectl get pod "$dst" -n "$dst_ns" -o wide --show-labels || exit 1
dst_ip=$(kubectl get pod "$dst" -n "$dst_ns" -o jsonpath='{.status.podIP}') || exit 1
[ -n "$dst_ip" ] || { echo '目标Pod没有IP' >&2; exit 1; }
echo '===== HTTP测试 ====='
kubectl exec -n "$src_ns" "$src" -- curl -m 5 -I "http://$dst_ip:$port"
echo "curl退出码: $?"
echo '===== 源端NetworkPolicy ====='
kubectl get netpol -n "$src_ns"
echo '===== 目标端NetworkPolicy ====='
if [ "$src_ns" != "$dst_ns" ]; then
kubectl get netpol -n "$dst_ns"
fi
echo '===== Calico节点状态(Calico集群适用) ====='
kubectl get pods -n kube-system -l k8s-app=calico-node -o wide
使用条件: 本机可以运行 kubectl,源 Pod 内装有 curl,目标服务为 HTTP。若测试 TCP、数据库或其他协议,改用对应的客户端工具。
脚本在资料包中可直接使用,文件名为 pod_net_diag.sh。
08 生产现场注意事项与复现资料说明
1. 生产操作前确认什么?
- 确认业务: 目标节点和 Pod 跑着什么服务,是否有关联业务。
- 保留现场: 记录报错时间、源/目标 Pod、节点、端口、NetworkPolicy 和近期变更。
- 只读定位: 先查配置、日志、路由和抓包,再决定要改什么。
- 控制变更范围: 网络策略按来源和端口最小放行,提前准备回退。
- 复测: 使用与故障发生时相同的请求,并让业务方确认实际功能。
2. 资料包包含什么?
| 文件 | 用途 |
|---|
namespace.yaml | 创建独立测试命名空间 |
pods.yaml | 在两个节点部署 curl 客户端和 Nginx |
deny-web.yaml | 模拟目标 Pod 入站被拦截 |
allow-client-to-web.yaml | 最小范围放行策略示例 |
pod_net_diag.sh | 通用只读排查脚本 |
README_pod_network_demo.md | 环境搭建和恢复说明 |
3. 怎么复现这次实测的 NetworkPolicy 故障?
只在独立测试集群执行。 先把 pods.yaml 中的节点名换成自己的两个工作节点,确认镜像能正常拉取。
kubectl apply -f namespace.yaml
kubectl apply -f pods.yaml
kubectl get pods -n pod-net-demo -o wide
记下 web 的 Pod IP,先确认能访问 Nginx;再添加拦截策略:
kubectl apply -f deny-web.yaml
kubectl describe netpol deny-web -n pod-net-demo
从 client 再次访问 web,验证超时。最后删除测试限制策略,确认通信恢复:
kubectl delete -f deny-web.yaml
如果想演示只放行必要流量,可以在保留 deny-web 的情况下添加 allow-client-to-web.yaml;它只允许 app=client 访问 app=web 的 TCP 80 端口。结束后按资料包 README 清理测试资源。
4. 参考资料