当你在浏览器输入 https://api.example.com/users 并按下回车时,这个请求会经过多少层网络转换才能到达 Kubernetes 集群中的某个 Pod?DNS 解析、TLS 终止、Ingress 路由、Service 负载均衡、iptables/IPVS DNAT、容器网络……每一层都有自己的转发逻辑和状态管理。
理解这条完整路径,是排查 Kubernetes 网络问题的基础。本文从底层视角,逐层追踪一个请求从客户端到 Pod 的完整旅程。
一、全局视角:请求的七层跳转
每一层的职责:
| 层次 | 组件 | 核心动作 |
|---|---|---|
| 1 | 客户端 DNS | api.example.com → 负载均衡器公网 IP |
| 2 | 云负载均衡器 | L4 转发到 Ingress Controller NodePort |
| 3 | Ingress Controller | TLS 终止,HTTP 路由匹配,转发到 Service |
| 4 | Service | ClusterIP 虚拟 IP,提供稳定入口 |
| 5 | kube-proxy | iptables/IPVS DNAT,ClusterIP → Pod IP |
| 6 | 节点网络 | 路由/网桥,跨 Node 或本地转发 |
| 7 | Pod | 容器内进程接收并处理请求 |
二、第一跳:DNS 解析
客户端 → DNS 服务器查询: api.example.com A 记录响应: 203.0.113.100(云负载均衡器公网 IP)如果集群使用 ExternalDNS,Ingress 创建时自动在云厂商 DNS 中创建 A 记录,指向 LoadBalancer Service 的外部 IP。
三、第二跳:云负载均衡器(L4)
客户端 → 203.0.113.100:443负载均衡器 → Node1:30080 或 Node2:30080(NodePort)云负载均衡器(如 AWS ALB/NLB)做 L4 层转发:
- 接收客户端 TCP 连接
- 健康检查后端 Node 的 NodePort
- 选择健康的 Node,将流量转发到
NodeIP:30080 - 保持连接跟踪(Connection Affinity)
负载均衡器转发到 NodePort 时,即使该 Node 上没有运行 Ingress Controller Pod,kube-proxy 的 iptables 规则也会将流量二次转发到有 Pod 的 Node。这是 iptables 模式的默认行为。
四、第三跳:Ingress Controller
NodeIP:30080 → Ingress Controller PodIngress Controller(以 NGINX Ingress 为例)的处理流程:
关键步骤:
- TLS 终止:使用 Ingress 中
tls.secretName指定的证书解密流量 - Host 路由:根据
Host头匹配 Ingress 规则 - Path 路由:根据 URL 路径匹配后端 Service
- 负载均衡:通过 Endpoints 列表选择后端 Pod,Ingress Controller 自己实现负载均衡(不依赖 kube-proxy)
NGINX Ingress Controller 默认使用 round-robin 算法选择后端 Pod,并且会检查 Pod 的 Ready 条件。它直接连接 Pod IP,绕过了 Service ClusterIP——这意味着 Ingress Controller 的流量不经过 kube-proxy。
五、第四跳:Service ClusterIP
当集群内部应用通过 Service 访问时(非 Ingress 路径),请求到达 Service ClusterIP:
Pod A → my-svc.default.svc.cluster.local:80DNS 解析 → 10.96.0.100:80(ClusterIP)ClusterIP 是一个虚拟 IP——它不存在于任何网络接口上,无法 ping 通。它只是一个 iptables/IPVS 规则的匹配条件。
六、第五跳:kube-proxy 与 DNAT
这是整个路径中最关键的一跳。kube-proxy 将目标地址从 ClusterIP 改写为 Pod IP(DNAT),使数据包能够到达实际的 Pod。
6.1 iptables 模式的完整规则链
# 1. PREROUTING 链:进入 Node 的流量-A PREROUTING -j KUBE-SERVICES
# 2. KUBE-SERVICES 链:匹配 Service ClusterIP-A KUBE-SERVICES -d 10.96.0.100/32 -j KUBE-SVC-MYAPP
# 3. KUBE-SVC 链:概率负载均衡-A KUBE-SVC-MYAPP -m statistic --mode random --probability 0.333 -j KUBE-SEP-POD1-A KUBE-SVC-MYAPP -m statistic --mode random --probability 0.500 -j KUBE-SEP-POD2-A KUBE-SVC-MYAPP -j KUBE-SEP-POD3
# 4. KUBE-SEP 链:DNAT 改写目标地址-A KUBE-SEP-POD1 -s 10.244.1.5/32 -j MARK --set-xmark 0x4000/0x4000-A KUBE-SEP-POD1 -j DNAT --to-destination 10.244.1.5:8080数据包转换过程:
原始: SRC=10.244.2.10 DST=10.96.0.100:80DNAT后: SRC=10.244.2.10 DST=10.244.1.5:80806.2 conntrack:连接跟踪
DNAT 发生后,Linux 内核的 conntrack 模块记录这条连接的映射关系:
原始: 10.244.2.10:45678 → 10.96.0.100:80DNAT: 10.244.2.10:45678 → 10.244.1.5:8080后续同一连接的数据包无需再次查 iptables 规则——conntrack 直接根据已有映射执行 DNAT,这是性能优化的关键。
回程数据包自动执行反向 DNAT(SNAT 的逆操作):
Pod 回复: SRC=10.244.1.5:8080 DST=10.244.2.10:45678反向DNAT: SRC=10.96.0.100:80 DST=10.244.2.10:456786.3 IPVS 模式的数据路径
IPVS 模式使用内核的 IPVS 模块,数据路径更短:
# IPVS 规则TCP 10.96.0.100:80 rr -> 10.244.1.5:8080 Masq 1 -> 10.244.2.3:8080 Masq 1 -> 10.244.3.7:8080 Masq 1IPVS 的优势在于:
- O(1) 查找:使用哈希表而非链式规则匹配
- 更丰富的算法:rr/wrr/lc/wlc/sh/dh/sed/nq
- 更少的 iptables 规则:IPVS 只处理 Service DNAT,其余(masquerade、NodePort)仍用 iptables
七、第六跳:节点网络转发
DNAT 后,数据包的目标地址是 Pod IP(如 10.244.1.5)。节点需要判断如何转发:
7.1 同节点转发
如果 Pod IP 属于当前 Node 的 Pod 网段:
目标: 10.244.1.5(本节点 Pod 网段 10.244.1.0/24)路由: 直接通过 cni0 网桥到达 Pod veth 对# 节点路由表10.244.1.0/24 dev cni0 proto kernel scope link src 10.244.1.17.2 跨节点转发
如果 Pod IP 属于其他 Node 的网段:
目标: 10.244.2.3(Node2 的 Pod 网段 10.244.2.0/24)路由: 通过 Node2 的物理 IP 转发# 节点路由表10.244.2.0/24 via 192.168.1.20 dev eth0跨节点转发的封装方式取决于 CNI 实现:
| CNI | 封装方式 | 性能 |
|---|---|---|
| Flannel (VXLAN) | VXLAN 封装,Overlay 网络 | 有封装开销 |
| Calico (BGP) | BGP 路由,无封装 | 接近原生性能 |
| Cilium (eBPF) | eBPF 路由/VXLAN | 高性能,可绕过 iptables |
| Weave Net | VXLAN 封装 | 有封装开销 |
八、第七跳:Pod 接收请求
数据包最终到达 Pod 的网络命名空间:
数据包: SRC=10.244.2.10:45678 DST=10.244.1.5:8080通过 veth pair → Pod eth0 → 容器内进程监听 8080 端口Pod 内进程看到的源地址取决于是否发生了 SNAT:
| 场景 | Pod 看到的源地址 |
|---|---|
| 同 Node Pod → Pod | 真实 Pod IP(无 SNAT) |
| 跨 Node Pod → Pod | 真实 Pod IP(CNI 路由,无 SNAT) |
| 外部 → NodePort → Pod | Node IP(kube-proxy 执行了 SNAT) |
NodePort 场景下,kube-proxy 执行 DNAT 后还会执行 SNAT(将源地址改写为 Node IP),否则 Pod 的回包无法正确路由。这导致 Pod 看不到真实客户端 IP。可以通过设置 externalTrafficPolicy: Local 避免 SNAT,但代价是流量只转发到本 Node 的 Pod。
九、完整路径追踪实战
使用 iptables -t nat -L -n -v 和 ipvsadm -Ln 可以在节点上查看实际的转发规则:
# 在 Node 上追踪请求路径
# 1. 查看 Service 规则iptables -t nat -L KUBE-SERVICES -n | grep 10.96.0.100
# 2. 查看负载均衡规则iptables -t nat -L KUBE-SVC-MYAPP -n
# 3. 查看 DNAT 目标iptables -t nat -L KUBE-SEP-POD1 -n
# 4. 查看连接跟踪表conntrack -L | grep 10.96.0.100
# 5. 查看路由ip route get 10.244.1.5
# 6. IPVS 模式查看规则ipvsadm -Ln -t 10.96.0.100:80总结
| 跳数 | 组件 | 关键操作 | 网络转换 |
|---|---|---|---|
| 1 | DNS | 域名 → 公网 IP | - |
| 2 | 云 LB | L4 转发到 NodePort | DST: 公网IP → NodeIP |
| 3 | Ingress Controller | TLS 终止 + HTTP 路由 | 解密 + 路由到 Service/Pod |
| 4 | Service | ClusterIP 虚拟入口 | - |
| 5 | kube-proxy | DNAT | DST: ClusterIP → PodIP |
| 6 | 节点网络 | 路由/网桥 | 同节点: cni0 网桥; 跨节点: 封装转发 |
| 7 | Pod | 容器接收 | veth pair → eth0 |
理解这条完整路径后,网络问题的排查就有了清晰的思路:从 Pod 往外逐跳检查——Pod 内网络是否正常?节点路由是否正确?kube-proxy 规则是否存在?Ingress 路由是否匹配?DNS 解析是否正确?
下一章将深入另一个维度的底层剖析——创建一个 Deployment 时,Kubernetes 控制面和节点组件的协作流程。
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时






