Kubernetes 网络进阶:IPVS 三种负载均衡模式(NAT / DR / TUN)详解
Kubernetes 网络进阶:IPVS 三种负载均衡模式(NAT / DR / TUN)详解
开头
写 [[《Kubernetes 核心网络枢纽:Service 与 Ingress 完全指南》|Service 那篇]] 的时候,我记了一笔:kube-proxy 有三种代理模式,iptables 是主流,IPVS 高性能。当时只是"知道有这回事"。这周回来看 kube-proxy,发现 IPVS 模式底下其实藏着一整套东西,源头是比 K8s 老得多的 LVS 项目。
然后我就栽了。翻开 LVS 的资料,迎面就是三种模式:NAT、DR、TUN。每个字都认识,连起来就是不明白。我整整一下午都在纠结同一个问题:这三种到底差在哪?
最崩溃的是看对比表格——“改 IP 还是改 MAC”“响应走不走 Director”,看完一遍合上书就混。NAT 和 DR 我反复记反,老觉得"DR 性能最好,是不是因为它改 IP 改得更彻底",结果正好相反,DR 恰恰是啥 IP 都不改。
这篇就把这三种模式掰开揉碎讲清楚,最后落到 K8s 为什么选 NAT(的变种)而不是 DR 上。
先交代环境:K8s 还是上篇那台 minikube(driver 用的 Docker);另外我为了看 LVS 真实的转发行为,在 VMware 里开了 3 台 CentOS 7 虚拟机搭了个最小实验环境(1 台 Director + 2 台 Real Server),都打了快照,翻车了能直接回滚。
一、先把缩写搞清楚
IPVS 这东西的缩写特别劝退,我一开始看到 VIP、RS、CIP 直接懵。捋一下:
| 缩写 | 全称 | 是啥 |
|---|---|---|
| LVS | Linux Virtual Server | Linux 内核里的负载均衡方案,常被称作"章文嵩的那个项目" |
| IPVS | IP Virtual Server | LVS 在内核中的实现模块,kube-proxy 的 IPVS 模式就是直接调它 |
| VIP | Virtual IP | 虚拟 IP,客户端访问的入口地址 |
| RS | Real Server | 真正干活的真实服务器 |
| CIP | Client IP | 客户端自己的 IP |
| Director | — | 跑 IPVS 的调度器,也叫 LB(Load Balancer) |
数据包的基本模型就一句话:
Client(CIP) → Director(VIP) → RS → Client
客户端只认 VIP,Director 负责把请求分发给后面的 RS。三种模式的区别,本质就是看这一路上到底动了什么。我把它们归结成四个维度,后面每讲一种模式都套这四个维度想,就不乱了:
- IP 改没改(目标 IP 从 VIP 改成 RS 的 IP?)
- MAC 改没改(二层上把包"快递"给谁?)
- 响应回不回 Director(回程流量要不要再绕一圈?)
- 能不能跨网段
二、NAT 模式(K8s 默认用的就是这个思路)
原理一句话
Director 做 DNAT,把目标 IP 从 VIP 改成选中的 RS 的 IP,回来再把源 IP 改回 VIP。 全程双向改 IP。
数据包全流程
Client
│ ① 请求目标 = VIP (192.168.100.100:80)
▼
Director
│ ② DNAT:目标 IP VIP → 192.168.1.10(某台 RS),源 IP 不动
▼
RS
│ ③ 处理完,响应目标 = Client IP
▼
Director ← 关键!响应也必须绕回 Director
│ ④ 把源 IP 从 RS 改回 VIP
▼
Client(看到的永远是 VIP 在回话)
核心操作
去程改目标 IP(VIP → RS),回程改源 IP(RS → VIP),是双向 NAT。因为 Director 改了目标 IP,RS 收到的请求源地址还是 Client 的,RS 响应时自然想直接回给 Client——但必须让它先回到 Director,Director 才能把源 IP 换回 VIP。所以有个硬性前提:
RS 的网关必须指向 Director。 不然 RS 的响应包直接发给 Client(或发给别的网关),Director 就再也拦不到回程,Client 收到的响应源 IP 是 RS 而不是 VIP,连接直接卡死。
关键配置
# Director 上:先开内核转发(NAT 模式必须)
echo 1 > /proc/sys/net/ipv4/ip_forward
# 配 VIP
ip addr add 192.168.100.100/24 dev ens33
# 加虚拟服务器,-s rr 是轮询调度;-m = masquerade,即 NAT 模式
ipvsadm -A -t 192.168.100.100:80 -s rr
ipvsadm -a -t 192.168.100.100:80 -r 192.168.1.10:80 -m
ipvsadm -a -t 192.168.100.100:80 -r 192.168.1.11:80 -m
RS 这边不用配 VIP,只要把默认网关指到 Director 就行,很省事。
优点 / 缺点 / 适用
| 说明 | |
|---|---|
| 优点 | 能跨网段、RS 零配置(不配 VIP)、端口还能映射(Service 端口 ≠ RS 端口,K8s 就是靠这个) |
| 缺点 | 请求和响应全走 Director,Director 是瓶颈;而且响应流量一般比请求大,瓶颈比你想的更明显 |
| 适用 | 中小规模、追求通用性——K8s 的 Service 转发就是典型场景 |
踩坑
我第一次搭 NAT 实验,curl 一直超时,tcpdump 看到请求明明到了 RS,响应就是发不回来。排查半天,是 RS 的网关忘了指到 Director。响应包被 RS 按默认路由丢给了另一个网关,Director 全程没看见回程,Client 等不到响应。
记住:NAT 模式下"响应必须原路返回",这不是细节,是模式成立的根基。
三、DR 模式(物理机生产常用,K8s 不用)
原理一句话
Director 只改目标 MAC 地址,把包在二层"快递"给选中的 RS,IP 一个字节都不动。
数据包全流程
Client
│ ① 请求目标 = VIP
▼
Director
│ ② 只改目标 MAC → 选中 RS 的 MAC,目标 IP 还是 VIP
▼
RS(看到目标 IP = VIP,正好自己"有"这个 VIP)
│ ③ 处理完,直接用 VIP 当源地址,响应直回 Client
▼
Client
核心操作
只改目标 MAC。Director 用 ARP 查到选中的 RS 的 MAC,把帧的目的 MAC 换成它,然后从网卡丢出去——因为是二层,RS 就在同一个局域网里,直接能收到。
RS 为什么认这个包?因为 RS 也"持有"VIP。注意这个前提,DR 的难点全在"怎么让多台机器同时持有 VIP 又不打架"。
关键配置(重点:VIP 配在 lo + ARP 抑制)
# Director:-g = gateway,即 DR 模式
ipvsadm -a -t 192.168.100.100:80 -r 192.168.100.11:80 -g
ipvsadm -a -t 192.168.100.100:80 -r 192.168.100.12:80 -g
# RS 上:VIP 一定要配在 lo(回环)上,不能配物理网卡
ip addr add 192.168.100.100/32 dev lo:0
# RS 上:ARP 抑制,别让内核拿 lo 上的 VIP 出去响应 ARP
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
这两条 sysctl 是 DR 的命门,我第一次直接跳过了,后果就是整个网段的 ARP 表被打乱。解释一下为什么:
网段里现在有多台机器都"持有"VIP——Director 的物理网卡上有,每台 RS 的 lo 上也有。如果客户端发一个"谁是 192.168.100.100"的 ARP 广播,所有 RS 都会抢答,ARP 表就乱了,流量会被分到莫名其妙的地方。
解决办法就是让 RS “闭嘴”:ARP 抑制。arp_ignore=1 意思是"只响应收到请求的那个接口上配置的 IP",lo 上虽然有 VIP,但请求不是从 lo 进来的,所以不响应;arp_announce=2 是"发 ARP 时用最合适的地址,不瞎报"。这样整个网段只有 Director 一个人认领 VIP。
优点 / 缺点 / 适用
| 说明 | |
|---|---|
| 优点 | 性能最高。Director 只处理一半流量(请求),响应直回,没有回程瓶颈 |
| 缺点 | 必须同局域网(二层可达,Director 才改得了 MAC);配置麻烦;而且 Director 不碰 IP,做不了端口映射——RS 必须监听跟 VIP 一样的端口 |
| 适用 | 物理机机房、流量大、追求极致性能的生产环境 |
坑:DR 的"响应不走 Director"不代表"请求不走 Director"。 请求必须先进 Director 做调度,不然谁来负载均衡?"请求经 Director、响应直回"才是 DR 的完整画像。
四、TUN 隧道模式(几乎不用)
原理一句话
Director 把原始数据包整个塞进一个新的 IP 包(IPIP 隧道),外层目标地址写成 RS 的真实 IP,像套了个信封寄过去。RS 拆开信封处理完,直接回 Client。
数据包全流程
Client → Director(套信封:外层目标 = RS 真实IP)
→ RS(拆信封,看到里面目标 IP 还是 VIP,处理)
→ Client(响应直回,不走 Director)
核心操作
不改原包的 IP 和 MAC,而是在外面包一层新的 IP 头(IPIP 封装)。这层新头的源是 Director、目标是 RS 的真实 IP。RS 收到后把外层拆掉,露出里面的 VIP 目标地址,正好自己 lo 上有 VIP,就处理了。
关键配置
# Director:-i = ipip,即 TUN 模式
ipvsadm -a -t 192.168.100.100:80 -r 192.168.200.10:80 -i
# RS 上:加载 ipip 模块,起隧道口,VIP 配在隧道口上
modprobe ipip
ip link set tunl0 up
ip addr add 192.168.100.100/32 dev tunl0
# 同样要 ARP 抑制
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
优点 / 缺点 / 适用
| 说明 | |
|---|---|
| 优点 | 能跨网段(信封外层的目标 IP 可以路由),响应还直回,Director 不受回程拖累 |
| 缺点 | 封装/拆封装有 CPU 开销;配置最复杂;中间网络设备得放行 IPIP 协议(协议号 4),有些防火墙默认不放行 |
| 适用 | 跨机房、跨数据中心,但实际部署很少见,属于"理论上很强、用起来很麻烦" |
我一开始以为 TUN 是 DR 的"跨网段升级版",忘了一个事:RS 也得配 VIP。它拆开信封,里面目标 IP 是 VIP,自己不持有 VIP 的话照样不认。所以 TUN 不是省事,是"能跨网段 + 更麻烦"。
五、三种模式横向对比(考前必看)
| 对比维度 | NAT | DR | TUN |
|---|---|---|---|
| 是否修改 IP | ✅ 改目标IP(回程改源IP) | ❌ 完全不动 | ❌ 不动(但外面套一层新IP头) |
| 是否修改 MAC | ✅ | ✅ | ❌ |
| 响应是否经过 Director | ✅ | ❌ | ❌ |
| 是否要求同网段 | ❌ | ✅ | ❌ |
| RS 是否需要配 VIP | ❌ | ✅(lo) | ✅(tunl0/lo) |
| 是否需要 ARP 抑制 | ❌ | ✅ | ✅ |
| 端口能否映射 | ✅ | ❌ | ✅ |
| 性能 | 低(回程瓶颈) | 高 | 中(封装开销) |
| 配置复杂度 | 低 | 中 | 高 |
我自编的记忆方法:
- NAT 改地址,DR 改门牌(MAC),TUN 套信封。
- 响应直回的只有 DR 和 TUN;响应必回 Director 的只有 NAT。
ipvsadm的三个参数-m/-g/-i对应 masquerade(NAT)/ gateway(DR)/ ipip(TUN)。
六、Kubernetes 为什么选 NAT(的变种)而不是 DR?
这是我看完三种模式后最大的疑问。K8s 不是追求性能吗?IPVS 都上了,为什么转发方法却用 NAT 而不是 DR?
把 K8s 的实际场景套进四个维度,答案就出来了:
- K8s 的 Service 转发本质是 DNAT:
ClusterIP:port → PodIP:port,端口都可能变。 而 DR 模式 Director 不碰 IP/端口,要求 RS 监听和 VIP 一样的端口——这跟 K8s 的port和targetPort分离的设计直接冲突。 - K8s 集群跨节点、跨网段。 DR 要求同局域网(Director 要能改目标 MAC),Pod 分布在各个节点甚至不同网段,条件根本不成立。
- Pod 会随时挂、随时补,后端列表是动态的。 这恰好是 IPVS 擅长的——内核哈希表维护后端列表,kube-proxy 实时同步。
所以 kube-proxy 的 IPVS 模式,转发方法默认就是 Masq(masquerade,NAT)。在 minikube 节点里能直接看到它生成的规则:
# 先确认 kube-proxy 是 IPVS 模式(上篇讲过)
curl -s 127.0.0.1:10249/proxyMode
# ipvs
# 节点里装一下 ipvsadm,然后看规则
sudo apt install -y ipvsadm
sudo ipvsadm -Ln
输出类似这样(每个 Service 一条虚拟服务器记录):
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Method ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 192.168.49.2:8443 Masq 0 0
TCP 10.96.0.10:53 rr
-> 172.17.0.2:53 Masq 0 0
Forward Method 清一色是 Masq,就是 NAT(masquerade)。kube-proxy 并没有用 DR 或 TUN。
那 NAT 的"回程瓶颈"在 K8s 里为啥能忍?因为 K8s 相比的基准是 iptables——iptables 规则是线性匹配,Service 一多转发就明显变慢;IPVS 是哈希表 O(1) 查找,规则再多也是常数时间。从 iptables 切到 IPVS,性能已经是质变,回程那点瓶颈在绝大多数集群规模下不是主要矛盾。
一句话:K8s 要的是"通用 + 能跨网段 + 能改端口 + 比 iptables 快",NAT 变种全占;DR 那种极致性能是给固定物理机房准备的,K8s 这种调度模型用不上。
我踩过的坑合集(考前必看)
| 坑 | 我的翻车经历 | 正确理解 |
|---|---|---|
| 以为"IPVS 模式 = DR 模式" | 觉得 IPVS 高性能就脑补成 DR | kube-proxy 的 IPVS 转发方法默认是 Masq(NAT),ipvsadm -Ln 一看便知 |
| NAT 和 DR 谁改 IP 记反 | 老觉得 DR 改 IP 更彻底 | DR 啥 IP 都不改,只改 MAC;NAT 才是改 IP 的那个 |
| NAT 忘了 RS 网关指向 Director | curl 超时,tcpdump 发现响应发不回来 | NAT 响应必须原路返回,RS 网关必须是指 Director |
| DR 没做 ARP 抑制 | 整个网段 ARP 表被打乱,流量乱跑 | 多台 RS 都"有"VIP,不抑制就会抢答 ARP |
| 以为 DR 能跨网段 | 想用 DR 连两个不同网段的 RS | DR 是二层转发,Director 要改 MAC,必须同局域网 |
| 以为 TUN 不用配 VIP | 拆开信封后 RS 不认这个包 | TUN 的 RS 也要配 VIP(在 tunl0/lo 上),且要 ARP 抑制 |
ipvsadm 参数 -m/-g/-i 混用 | 拿 -m 配置 DR,行为完全不对 | -m=NAT(masquerade)、-g=DR(gateway)、-i=TUN(ipip) |
最后说两句
写这篇的过程就是把"IPVS"从一行笔记变成一张图的过程:先在 3 台 CentOS 上把三种模式各搭了一遍(NAT 网关忘配、DR 忘 ARP 抑制都现场翻车),再回到 minikube 里 ipvsadm -Ln 看 kube-proxy 到底生成了什么规则。绕了这一圈,才真正理解 [[《Kubernetes 核心网络枢纽:Service 与 Ingress 完全指南》|Service 那篇]]里写的"iptables 线性匹配 vs IPVS 哈希查找"是什么意思。
还没完全搞懂的地方:DR 模式在大规模机房里的 ARP 抑制细节,我只在实验环境验证过,真实生产里几百台 RS 的广播域怎么收敛,没概念;TUN 模式在我这基本属于"知道原理、这辈子估计用不上";IPVS 的调度算法也只熟 rr 和 wrr,lc(最少连接)到底什么时候比轮询好,还没吃透。
对了,翻回 [[7.28 Linux网络核心进阶:TCP内核参数、ss实战、NAT与防火墙原理]],NAT 那张"改了源/目标 IP 必须原路返回"的图,跟这次 IPVS 的 NAT 模式完全是同一件事——学过的东西真的会串起来。
更多推荐
所有评论(0)