跳到主要内容

K8s/网络 生产排查台账:Pod 无法通信,怎么定位和处理?

01 前置理论与核心排查思路​

1. 先弄清 Pod 之间的通信链路​

直接访问 Pod IP:

源 Pod 发请求 → 源节点网络 → 目标节点网络 → 目标 Pod → 应用端口。

  • 同节点: 主要经过节点内的虚拟网卡、路由和网络规则。
  • 跨节点: 还要经过节点间的路由或隧道,例如 IPIP、VXLAN。
  • NetworkPolicy: 控制哪些 Pod、哪些端口允许通信,由支持策略的 CNI 组件执行。

通过 Service 访问:

客户端 → Service IP → Service 转发规则 → 后端 Pod IP → 应用端口。

通过域名访问时,最前面还要加一步 DNS 解析。

理解这两条链路,就能把故障定位到具体环节。

2. 出现什么现象,优先查哪里?​

故障现象优先排查
Pod 没启动、反复重启Pod 事件、容器日志、探针、镜像
Pod Running,但本地业务端口不通应用进程、监听地址、端口
本地服务正常,Pod IP 访问超时NetworkPolicy、CNI、节点网络
同节点正常,跨节点不通节点路由、IPIP/VXLAN、防火墙
Pod IP 正常,Service IP 不通Service selector、targetPort、EndpointSlice、转发规则
Service IP 正常,域名访问失败CoreDNS、Pod DNS 配置、DNS 出站策略
偶发超时或部分节点异常节点负载、丢包、连接跟踪、CNI 日志

通用顺序:先测业务端口,再判断是 Pod IP、Service 还是 DNS 哪一层出了问题。

3. 几个网络组件分别做什么?​

组件作用
CNI(如 Calico、Flannel)给 Pod 配网络,让 Pod 能互相通信
NetworkPolicy按 Pod 标签、来源、端口控制流量
IPIP / VXLAN在节点之间传输 Pod 网络数据
Service给一组后端 Pod 提供稳定访问入口
EndpointSlice记录 Service 实际转发到哪些 Pod 和端口
kube-proxy 或其他 Service 数据面实现 Service 到后端的流量转发
CoreDNS把 Service 域名解析成 IP

Flannel 单独使用时通常不执行 NetworkPolicy;Calico 支持网络策略。创建 NetworkPolicy 后,还需要 CNI 支持,限制才能生效。


02 故障排查与验证 SOP​

这一章使用通用命令。示例中的 app-ns、client、web、Pod IP 和端口都换成现场信息。命令默认只查询或发起测试请求。

步骤一:确认故障对象和范围​

先找出源 Pod、目标 Pod、所在节点和 IP:

kubectl get pods -A -o wide

再看目标命名空间的 Pod 标签:

kubectl get pods -n app-ns -o wide --show-labels

主要记录五项:源 Pod、目标 Pod、源/目标节点、目标 IP、业务端口。

如果 Pod 本身异常,直接查事件和日志:

kubectl describe pod web -n app-ns
kubectl logs web -n app-ns --tail=50

Running 表示容器正在运行,业务端口仍要单独检查。READY 未就绪时,还要检查健康探针和应用启动日志。

步骤二:先确认应用和业务端口正常​

下面以 HTTP 80 端口为例。先在目标 Pod 内部访问本地服务:

kubectl exec -n app-ns web -- wget -S --spider localhost:80

再访问目标 Pod 自己的 IP:

kubectl exec -n app-ns web -- wget -S --spider 10.244.1.20:80
  • localhost 成功,Pod IP 失败:重点查应用是否只监听 127.0.0.1。
  • 两者都失败:查应用启动状态、监听端口和日志。
  • 两者都成功:继续从源 Pod 测试。

从源 Pod 请求目标 Pod IP:

kubectl exec -n app-ns client -- curl -m 5 -I 10.244.1.20:80

这里假设客户端容器带有 curl。其他协议要用对应客户端,不能用 HTTP 请求代替数据库等业务测试。

请求结果下一步
200 OK这次 HTTP 请求成功;继续检查 Service 或域名
Connection refused检查端口监听、目标地址或主动拒绝规则
Connection timed out检查 NetworkPolicy、路由、防火墙、丢包
Could not resolve host检查 DNS;若用的是纯 IP,则不会出现域名解析问题

步骤三:区分同节点和跨节点故障​

kubectl get pods -A -o wide

找同节点和跨节点的测试对象,分别测试相同协议和端口:

  • 同节点成功、跨节点失败: 优先查节点之间的路由、隧道、防火墙。
  • 只有某个目标 Pod 不通: 优先查目标端口、标签和网络策略。
  • 某台节点上的 Pod 普遍不通: 优先查该节点的 CNI、路由和网络状态。
  • 整个集群访问 Service 异常: 先看 Service、后端和转发组件。

步骤四:检查 NetworkPolicy​

先列出策略:

kubectl get netpol -A

查看目标命名空间的具体策略:

kubectl describe netpol 策略名 -n app-ns
kubectl get netpol -n app-ns -o yaml

重点看四个位置:

  1. podSelector: 策略选中了哪些标签的 Pod。
  2. Ingress: 目标 Pod 允许谁访问、允许哪些端口。
  3. Egress: 源 Pod 能访问哪里、能走哪些端口。
  4. 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 走哪条路:

ip route get 10.244.1.20

IPIP 模式下查看隧道设备:

ip -d link show tunl0

查看节点防火墙规则:

sudo iptables -S

如果确认使用 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 配置:

cat /etc/resolv.conf

上面两条在客户端容器内执行。若容器缺少 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。

排查顺序:

  1. 对比同节点、跨节点的业务端口测试。
  2. 查 NetworkPolicy,确认没有针对源或目标的拦截。
  3. 查 CNI 使用 IPIP、VXLAN 还是纯路由。
  4. 查源节点到目标 Pod IP 的路由。
  5. 两侧抓包,确认数据在哪一段丢失。

关键命令:

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 时再看监听地址:

ss -lnt

处理: 把应用监听地址调整为 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 wideIP、NODE、STATUS
Pod 标签kubectl get pods -n app-ns --show-labelsLABELS
Pod 事件kubectl describe pod web -n app-nsEvents
应用日志kubectl logs web -n app-ns --tail=50启动和异常日志
容器内 HTTPkubectl exec -n app-ns web -- wget -S --spider localhost:80HTTP 状态
Pod IP HTTPkubectl exec -n app-ns client -- curl -m 5 -I 10.244.1.20:80成功、拒绝、超时
网络策略kubectl get netpol -A哪些命名空间有策略
策略详情kubectl describe netpol 策略名 -n app-nsselector、Ingress、Egress
Calico 状态kubectl get pods -n kube-system -l k8s-app=calico-nodeREADY、RESTARTS
Calico 日志kubectl logs -n kube-system calico-node-xxxxx -c calico-node --tail=100Felix、路由、IP 错误
Calico 网络模式kubectl get ippools.crd.projectcalico.org -o yamlCIDR、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-nsselector、port、targetPort
Service 后端kubectl get endpointslice -n app-ns -l kubernetes.io/service-name=web-svc后端 IP 和端口
CoreDNSkubectl get pods -n kube-system -l k8s-app=kube-dnsPod 状态
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. 生产操作前确认什么?​

  1. 确认业务: 目标节点和 Pod 跑着什么服务,是否有关联业务。
  2. 保留现场: 记录报错时间、源/目标 Pod、节点、端口、NetworkPolicy 和近期变更。
  3. 只读定位: 先查配置、日志、路由和抓包,再决定要改什么。
  4. 控制变更范围: 网络策略按来源和端口最小放行,提前准备回退。
  5. 复测: 使用与故障发生时相同的请求,并让业务方确认实际功能。

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. 参考资料​

完整内容已隐藏

请联系作者或在线获取阅读密码。