一次请求在集群里走的路

K8s 网络排障难,是因为一条请求要穿过好几层:客户端 → Ingress(七层入口)→ Service(四层负载)→ Endpoints(真实 Pod IP)→ 容器网络(CNI)。每一层都可能出问题,而且症状都是「访问不通」。排障的第一步,就是先确定请求卡在哪一层,而不是在应用层瞎查。

可以把流量分成两个方向:南北向(集群外到集群内,走 Ingress/NodePort/LoadBalancer)和东西向(Pod 到 Pod、Pod 到 Service,走 ClusterIP)。故障范围也能据此粗分:只影响集群外访问,问题多半在 Ingress 或入口层;集群内互相访问也不通,问题多半在 CNI 或 kube-proxy。

# 网络排障第一问:哪里通、哪里不通
kubectl get svc,ep -A                     # 服务与后端端点是否就绪
kubectl get pods -A -o wide               # 看 Pod IP 与所在节点
kubectl get ingress -A                    # 入口规则是否正常

# 分层探测顺序
curl http://<pod-ip>                       # Pod 层(最底层)
curl http://<clusterip>                    # Service 层
curl https://<ingress-host>                # 入口层(最上层)
本文核心知识点
  • 分层按 Pod → Service → Ingress 逐层收敛故障。
  • CNIPod 网络由 veth + 网桥 + 路由实现。
  • 转发Service 靠 kube-proxy 生成规则并依赖 Endpoints。
  • 解析集群内 DNS 由 CoreDNS 承担,带 search domain。
Kubernetes 网络配图:中央网关方块向下分发流动光线到一排 Pod 方块、左侧桥形图标、右侧圆柱体与闸门图标连成网状拓扑的蓝色扁平科技插画
把请求路径拆成 Pod、Service、Ingress 三层,逐层验证,网络问题就不难。

CNI 与 Pod 网络:第一层连通性

每个 Pod 都有自己的 IP,这靠的是 CNI(容器网络接口)插件。最简模型:Pod 里一块 veth 虚拟网卡连到节点上的网桥(cni0),节点间再通过路由或隧道打通。主流实现里,Calico 用 BGP 直连路由(性能好、可配网络策略),Flannel 用 VXLAN 隧道(简单、跨子网友好),Cilium 用 eBPF 实现(性能与可观测性最强)。

Pod 间不通,先分清是「同一节点不通」还是「跨节点不通」。同节点不通多半是网桥或 veth 问题,跨节点不通多半是路由、隧道或防火墙问题。快速定位用 ping Pod IP,再逐个检查节点的路由表和 CNI 状态。

# Pod 网络层排查
kubectl get pods -n kube-system | grep -E 'calico|flannel|cilium'
kubectl -n kube-system logs -l k8s-app=calico-node   # CNI 组件日志

# 进节点看路由(Pod 网段怎么走)
ip route show
# 常见输出:10.244.1.0/24 via 192.168.1.2 dev eth0(Calico BGP)
#          10.244.0.0/16 dev flannel.1(Flannel VXLAN)

# 检查 veth 是否成对
ethtool -S eth0 2>/dev/null | head -5   # Pod 侧
ip link show | grep veth                 # 节点侧

还有一个高频坑:节点安全组/防火墙挡了 CNI 所需的端口(Calico 的 BGP 179、VXLAN 的 4789、健康检查端口等),导致新节点上的 Pod 永远跨不过去。加完节点发现跨节点不通,优先怀疑安全组。

Service 与 Endpoints:负载与转发

Service 是 Pod 的稳定入口:ClusterIP 集群内访问,NodePort 在每台节点上开端口,LoadBalancer 交给云厂商负载均衡器。Service 本身不转发流量,真正干活的是 kube-proxy(iptables 或 IPVS 模式)加上后端 Pod 的 Endpoints。

「Service 访问不通」先看 Endpoints:kubectl get ep 里如果没有后端地址,说明 Pod 没打上 Service 的 selector 标签,或者 Pod 不在 ready 状态。这是最高频的 Service 故障原因,比怀疑 kube-proxy 要常见得多。

# Service 排查三步
kubectl get svc <svc> -n <ns> -o yaml      # 看 selector 与 type
kubectl get ep <svc> -n <ns>               # Endpoints 是否就绪(关键!)
kubectl get pods -n <ns> --show-labels     # Pod 标签是否匹配 selector

# 确认 kube-proxy 模式(iptables 还是 ipvs)
kubectl -n kube-system get cm kube-proxy -o yaml | grep mode

Endpoints 正常仍不通,再查 kube-proxy 与节点 iptables/ipvs 规则。IPVS 模式下 ipvsadm -ln 能看到 Service 的虚拟 IP 和后端列表;iptables 模式下规则链很长,别直接读,用 curl ClusterIP 实测更快。会话保持(source IP 透传)需求会影响 externalTrafficPolicy 的选择,配错了会出现「节点间跳转后客户端 IP 全变成节点 IP」的怪现象。

Ingress 与南北向流量

集群外访问通常走 Ingress,最常见实现是 ingress-nginx(Nginx 控制器,七层)。Ingress 资源声明「哪个域名/路径转发到哪个 Service」,控制器把规则落成 Nginx 配置。南北向问题集中在三块:域名解析与证书、Ingress 规则本身、控制器到后端 Service 的转发。

证书问题最常见也最隐蔽:证书过期、证书与域名不匹配(SAN 缺失)、secret 不存在。出现「浏览器报证书错误但服务其实正常」,先看 Ingress 的 TLS 段引用的 secret 是否真实存在且未过期。

# Ingress 排查
kubectl get ingress -n <ns> -o yaml        # 看规则与 TLS
kubectl -n ingress-nginx get pod           # 控制器是否正常
kubectl -n ingress-nginx logs -l app.kubernetes.io/name=ingress-nginx   # 控制器日志

# 证书检查
kubectl get secret <tls-secret> -n <ns> -o jsonpath='{.data.tls\.crt}' |
  base64 -d | openssl x509 -noout -dates -subject

如果 Ingress 控制器日志显示转发 502/504,多半是后端 Service 或 Pod 的问题,回到第 3 节继续查;如果日志干净但外部访问超时,则是入口负载(云 LB / NodePort)到控制器的链路问题。记住:Ingress 只是把外部流量导到 Service,它自己不产生后端故障。