ClusterIP 流量路径
客户端 Pod → ClusterIP → kube-proxy 规则(iptables/IPVS) → DNAT → 后端 Pod(可能跨节点)
- 不涉及 Node 端口:与 NodePort/LoadBalancer 不同,ClusterIP 仅通过集群内部虚拟 IP 转发。
- 跨节点依赖 CNI:由 CNI 插件(如 Calico、Flannel)实现 Pod 间的跨节点通信。
- 无 SNAT:集群内流量保留客户端 Pod IP
举例子
- 假设:
Service 的 ClusterIP: 10.96.1.2,端口 80。
后端 Pod: 172.16.1.2:9376(运行在 NodeA 上),172.16.2.3:9376(运行在 NodeB 上)
- (1)kube-proxy 会创建类似以下规则
# 1. 匹配目标为 ClusterIP 的流量
-A KUBE-SERVICES -d 10.96.1.2/32 -p tcp --dport 80 -j KUBE-SVC-XXXX
解释:(匹配目标为 ClusterIP 的流量)
-A KUBE-SERVICES
将规则追加到 KUBE-SERVICES 链(Kubernetes 自定义链,用于处理所有 Service 流量)。
-d 10.96.1.2/32
匹配目标 IP 为 10.96.1.2(Service 的 ClusterIP),/32 表示精确匹配。
-p tcp --dport 80
匹配 TCP 协议且目标端口为 80(Service 的端口)。
-j KUBE-SVC-XXXX
跳转到 KUBE-SVC-XXXX 链(该 Service 专用的负载均衡链)。
作用:
将所有发往 10.96.1.2:80 的流量交给 KUBE-SVC-XXXX 链处理
# 2. 负载均衡到后端 Pod(概率随机分发)
-A KUBE-SVC-XXXX -m statistic --mode random --probability 0.5 -j KUBE-SEP-YYYY1
-A KUBE-SVC-XXXX -j KUBE-SEP-YYYY2
解释:(负载均衡到后端 Pod)
第一条负载均衡规则
-m statistic --mode random --probability 0.5
使用 statistic 模块进行概率匹配:
--mode random:随机模式。
--probability 0.5:50% 的概率匹配该规则。
-j KUBE-SEP-YYYY1
如果匹配成功(50% 概率),跳转到 KUBE-SEP-YYYY1 链(对应第一个后端 Pod)。
第二条负载均衡规则
-j KUBE-SEP-YYYY2
如果未匹配第一条规则(剩余 50% 概率),跳转到 KUBE-SEP-YYYY2 链(对应第二个后端 Pod)
作用:
实现简单的随机负载均衡,将流量均匀分发到两个后端 Pod。
# 3. DNAT 规则:将 ClusterIP 转换为 Pod IP
-A KUBE-SEP-YYYY1 -p tcp -j DNAT --to-destination 172.16.1.2:9376 # Pod 在 NodeA
-A KUBE-SEP-YYYY2 -p tcp -j DNAT --to-destination 172.16.2.3:9376 # Pod 在 NodeB
解释:(DNAT 转换(目标地址转换)
第一条 DNAT 规则
-j DNAT --to-destination 172.16.1.2:9376
将数据包的目标 IP 和端口从 ClusterIP:80 修改为 172.16.1.2:9376(第一个 Pod 的 IP 和端口)。
第二条 DNAT 规则
-j DNAT --to-destination 172.16.2.3:9376
将目标地址修改为 172.16.2.3:9376(第二个 Pod 的 IP 和端口)。
作用:
完成从 Service 虚拟 IP 到实际 Pod IP 的转换,使流量最终到达后端 Pod。
规则链的层级关系
KUBE-SERVICES:所有 Service 流量的入口链。
KUBE-SVC-XXXX:单个 Service 的负载均衡链。
KUBE-SEP-YYYY:单个后端 Pod(Endpoint)的 DNAT 链。
- (2)流量转发流程
客户端 Pod(如 172.16.3.4)发起请求到 10.96.1.2:80。
数据包进入内核协议栈,匹配 KUBE-SERVICES 链的规则。
根据负载均衡策略(如随机),选择一条 KUBE-SEP-YYYY 规则。
DNAT 生效:目标 IP 从 10.96.1.2:80 改为 172.16.1.2:9376(假设选中 NodeA 的 Pod)。
数据包通过 CNI 插件(如 Calico、Flannel) 跨节点路由到 NodeA 的 Pod(如果客户端与 Pod 不在同一节点)。
调试技巧
- 查看完整 iptables 规则
conntrack -L -d 10.96.1.2 -p tcp --dport 80
- 检查 DNAT 转换结果
tcp src=172.16.3.4 dst=10.96.1.2 sport=12345 dport=80 \
[DNAT] to=172.16.1.2:9376
- 检查所有 Node 的 iptables 规则
# 在任意 Node 上执行
iptables -t nat -L KUBE-SERVICES -n | grep 10.96.1.2
- 对比不同 Node 的 DNAT 规则
# 在 NodeA 和 NodeB 上分别执行
iptables -t nat -L KUBE-SVC-XXXX -n
替换为 IPVS 规则
# 查看 IPVS 规则
ipvsadm -Ln
# 输出示例
TCP 10.96.1.2:80 rr # ClusterIP 服务,调度算法为轮询(rr)
-> 172.16.1.2:9376 Masq 1 0 0 # 后端 Pod1
-> 172.16.2.3:9376 Masq 1 0 0 # 后端 Pod2
关键变化点
(1) 负载均衡算法的差异
iptables:
使用 statistic 模块的随机概率分发(概率权重)。
IPVS:
支持多种调度算法(如 rr、lc、sh),默认 rr(轮询)。(2) 规则存储方式
iptables:
规则以链式结构存储在内核的 nat 表中,线性匹配效率较低(O(n))。
IPVS:
规则以哈希表存储,查找效率为 O(1),适合大规模 Service。(3) NAT 行为的保留
SNAT(Masq):
IPVS 默认启用 Masq(类似 iptables 的 MASQUERADE),确保回复流量经过节点。
DNAT:
IPVS 直接修改目标地址,无需显式 DNAT 规则。
总结
- 每个 Node 上的 kube-proxy 会维护基本相同的 iptables/IPVS 规则,但具体规则细节会根据该 Node 上是否运行相关 Pod 而略有差异
- 确保无论从哪个 Node 或 Pod 访问 ClusterIP,都能正确负载均衡到后端 Pod
- 实现: 可能跨节点(依赖 CNI)
- 例外情况
externalTrafficPolicy: Local:
仅适用于 NodePort/LoadBalancer,对 ClusterIP 无影响。