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 直接懵。捋一下:

缩写全称是啥
LVSLinux Virtual ServerLinux 内核里的负载均衡方案,常被称作"章文嵩的那个项目"
IPVSIP Virtual ServerLVS 在内核中的实现模块,kube-proxy 的 IPVS 模式就是直接调它
VIPVirtual IP虚拟 IP,客户端访问的入口地址
RSReal Server真正干活的真实服务器
CIPClient IP客户端自己的 IP
Director跑 IPVS 的调度器,也叫 LB(Load Balancer)

数据包的基本模型就一句话:

Client(CIP)  →  Director(VIP)  →  RS  →  Client

客户端只认 VIP,Director 负责把请求分发给后面的 RS。三种模式的区别,本质就是看这一路上到底动了什么。我把它们归结成四个维度,后面每讲一种模式都套这四个维度想,就不乱了:

  1. IP 改没改(目标 IP 从 VIP 改成 RS 的 IP?)
  2. MAC 改没改(二层上把包"快递"给谁?)
  3. 响应回不回 Director(回程流量要不要再绕一圈?)
  4. 能不能跨网段

二、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 不是省事,是"能跨网段 + 更麻烦"。


五、三种模式横向对比(考前必看)

对比维度NATDRTUN
是否修改 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 的实际场景套进四个维度,答案就出来了:

  1. K8s 的 Service 转发本质是 DNAT:ClusterIP:port → PodIP:port,端口都可能变。 而 DR 模式 Director 不碰 IP/端口,要求 RS 监听和 VIP 一样的端口——这跟 K8s 的 porttargetPort 分离的设计直接冲突。
  2. K8s 集群跨节点、跨网段。 DR 要求同局域网(Director 要能改目标 MAC),Pod 分布在各个节点甚至不同网段,条件根本不成立。
  3. 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 高性能就脑补成 DRkube-proxy 的 IPVS 转发方法默认是 Masq(NAT)ipvsadm -Ln 一看便知
NAT 和 DR 谁改 IP 记反老觉得 DR 改 IP 更彻底DR 啥 IP 都不改,只改 MAC;NAT 才是改 IP 的那个
NAT 忘了 RS 网关指向 Directorcurl 超时,tcpdump 发现响应发不回来NAT 响应必须原路返回,RS 网关必须是指 Director
DR 没做 ARP 抑制整个网段 ARP 表被打乱,流量乱跑多台 RS 都"有"VIP,不抑制就会抢答 ARP
以为 DR 能跨网段想用 DR 连两个不同网段的 RSDR 是二层转发,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 的调度算法也只熟 rrwrrlc(最少连接)到底什么时候比轮询好,还没吃透。

对了,翻回 [[7.28 Linux网络核心进阶:TCP内核参数、ss实战、NAT与防火墙原理]],NAT 那张"改了源/目标 IP 必须原路返回"的图,跟这次 IPVS 的 NAT 模式完全是同一件事——学过的东西真的会串起来。

更多推荐