iptables 模式详解
iptables 模式是 Kubernetes 从 v1.2 版本开始采用的默认 Service 代理模式,用于替代性能较差的 userspace 模式。该模式利用 Linux 内核的 iptables 功能,在 netfilter 框架中直接完成数据包的目的地址转换(DNAT),避免了用户态与内核态之间的频繁切换,大幅提升了 Service 的转发性能。
iptables 与 netfilter 基础
- netfilter:Linux 内核中的一个框架,在网络协议栈的不同位置(钩子点)注册回调函数,允许对数据包进行修改、过滤或重定向。
- iptables:用户空间的命令行工具,用于配置 netfilter 的规则表(filter、nat、mangle 等)。kube-proxy 使用 iptables 的
nat表来实现 Service 的 DNAT。
当一个数据包进入节点内核时,会依次经过 PREROUTING、FORWARD、POSTROUTING 等钩子点。kube-proxy 在 PREROUTING 和 OUTPUT 链中插入自定义规则,将发往 Service IP 的流量劫持并重定向到后端 Pod。
工作原理
kube-proxy 以 iptables 模式运行时,会持续监听 API Server 中 Service 和 Endpoints 的变化,并据此刷新节点上的 iptables 规则。其核心机制是:
- 创建 KUBE-SERVICES 链:kube-proxy 在 nat 表中建立一个自定义链
KUBE-SERVICES,并在 PREROUTING 和 OUTPUT 链中跳转到该链。 - 为每个 Service 添加匹配规则:对于每个 Service(ClusterIP 类型),在
KUBE-SERVICES链中添加一条规则,匹配目标 IP 为 Service ClusterIP、目标端口为 Service Port 的数据包,然后跳转到以KUBE-SVC-<hash>命名的专用链。 - 负载均衡与 DNAT:
KUBE-SVC-<hash>链中包含若干条统计随机规则(例如使用statistic模块的random模式),每条规则按概率匹配并跳转到KUBE-SEP-<hash>链。每一条KUBE-SEP-<hash>链对应一个后端 Pod,其规则会将数据包的目标地址和端口修改为该 Pod 的 IP 和容器端口(DNAT)。 - 回程路径处理:当后端 Pod 返回响应时,响应数据包的源地址是 Pod IP,目标地址是客户端 IP。由于之前已经通过 DNAT 修改过连接跟踪(conntrack)表,内核会自动将响应数据包的源地址还原为 Service IP,客户端无需感知后端变化。
配置示例与规则查看
可以通过以下命令查看节点上的 iptables 规则(需要进入 kube-proxy 所在节点或使用 nsenter):
# 查看 nat 表中 KUBE-SERVICES 链的规则
iptables -t nat -L KUBE-SERVICES -n
# 查看某个 Service 对应的 KUBE-SVC 链
iptables -t nat -L KUBE-SVC-XYZ -n一个简化的示例(假设 Service ClusterIP 为 10.96.0.10,端口 80,有两个后端 Pod IP 10.244.1.2 和 10.244.2.3):
# KUBE-SERVICES 链中的条目
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp --dport 80 -j KUBE-SVC-ABCD
# KUBE-SVC-ABCD 链:50% 概率到第一个 SEP,剩余继续匹配
-A KUBE-SVC-ABCD -m statistic --mode random --probability 0.5 -j KUBE-SEP-1
-A KUBE-SVC-ABCD -j KUBE-SEP-2
# KUBE-SEP-1 链:执行 DNAT 到第一个 Pod
-A KUBE-SEP-1 -p tcp -j DNAT --to-destination 10.244.1.2:80负载均衡算法
- 默认算法:通过
statistic模块的random概率匹配实现随机分发(不是轮询)。对于 n 个后端,每条规则的权重相等(概率为 1/n)。 - 会话亲和性:通过设置
--dport和连接跟踪的超时时间可以实现ClientIP会话亲和。具体是在KUBE-SVC链中增加-m recent --set等规则,将同一客户端 IP 的后续请求导向同一个KUBE-SEP。
优点
- 性能较高:所有处理都在内核态完成,避免了 userspace 模式中的用户态/内核态上下文切换,转发延迟低,吞吐量高。
- 实现简单:不需要运行额外的用户态代理进程(虽然 kube-proxy 依然运行,但仅负责规则刷新,不处理每条请求)。
- 对 Pod 透明:后端 Pod 可以直接看到真实客户端 IP(通过修改 iptables 规则中的
--to-destination配合--preserve-literal可能做不到完全保留,但配合externalTrafficPolicy: Local可解决),支持源 IP 白名单等需求。
缺点与限制
- 规则数量线性增长:每个 Service 及其每个后端 Pod 都会产生多条 iptables 规则。当 Service 数量达到几千甚至上万级别时,节点上的 iptables 规则集变得非常庞大(可能几十万条),导致:
iptables-restore刷新规则时间显著增长(从秒级到分钟级),影响 Service 更新的时效性。- 数据包遍历链的时间增加,CPU 使用率升高。
- 不支持更复杂的负载均衡算法:iptables 仅支持随机分发(基于概率),不支持加权最少连接、IP 哈希等高级算法。
- 连接跟踪(conntrack)负载:每个连接都需要在 conntrack 表中记录 DNAT 映射,高并发下 conntrack 表可能成为瓶颈(可通过调整内核参数缓解)。
- 调试困难:当规则数量庞大时,排查数据包转发路径需要深入分析 iptables 链,较为复杂。
与 userspace 模式的对比
| 特性 | iptables 模式 | userspace 模式 |
|---|---|---|
| 数据包处理位置 | 内核态(netfilter) | 用户态(kube-proxy 进程) |
| 模式切换 | 无 | 每次请求多次内核-用户切换 |
| 性能 | 高,适合中大规模集群 | 低,仅适合极小规模测试 |
| 负载均衡算法 | 随机概率 | 轮询 |
| 源 IP 保留 | 支持(需配置 externalTrafficPolicy) | 不支持 |
| 可扩展性 | 中等,规则数量瓶颈 | 极低,kube-proxy 单点瓶颈 |
| 当前状态 | Kubernetes 默认模式 | 废弃 |
适用场景与使用建议
iptables 模式是 Kubernetes 默认且可靠的 Service 代理模式,适用于大多数生产环境,尤其是以下场景:
- 集群规模中等(节点数 < 100,Service 数量 < 2000)。
- 对延迟和吞吐量有较高要求,但不是极致性能(超大规模集群)。
- 需要保留客户端源 IP 的 Service(可配合
spec.externalTrafficPolicy: Local)。
当 Service 数量超过 5000 或节点数量达到数百时,iptables 模式的规则刷新延迟和内存占用会成为问题,此时应考虑切换到 ipvs 模式。
切换到 ipvs 模式
若需要从 iptables 模式切换到 ipvs 模式,需要确保:
- 内核加载了
ip_vs、ip_vs_rr、ip_vs_wrr、ip_vs_sh等模块。 - kube-proxy 启动参数中添加
--proxy-mode=ipvs。 - 安装
ipset工具(ipvs 模式依赖)。
切换步骤一般通过修改 kube-proxy 的 ConfigMap(在 kube-system 命名空间)完成,然后重启 kube-proxy Pod。
总结
iptables 模式作为 Kubernetes Service 机制的成熟实现,在性能和实现复杂度之间取得了合理的平衡,是绝大多数集群部署的默认选择。理解其基于内核 DNAT 的工作原理、规则结构和限制,有助于在日常运维中诊断网络问题,并在集群规模增长到瓶颈时,顺利过渡到 ipvs 模式。
