bigywater.tech
Kubernetes · 72

kube-proxy 的 ipvs 与 nftables 模式

kube-proxy 的 ipvs 和 nftables 模式到底和 iptables 有什么不同?Service 在内核里长什么样?规则量差多少?这篇各起一个集群,读 /proc/net/ip_vs 和 nft 规则集,并对比 300 个 Service 之后的规则数量与生效时间。

100 / 100 / 100
ipvs 的 rr 调度器分配 300 个新连接,比 iptables / nftables 的随机抽签均匀
+4500 行
再创建 300 个 Service 时,iptables 模式新增的 iptables-save 行数;ipvs 模式的 iptables 保持 85 行
14~15 秒
三种模式下 300 个 Service 全部可访问所需的时间,基本相同

ipvs:内核里的虚拟服务器

实测 · 本机执行输出
  集群 kx-ipvs:kube-proxy 配置 mode=ipvs
  Service web 的 ClusterIP 10.96.33.226(十六进制 0A6021E2),3 个后端 Pod IP 末尾 ['1.2', '1.3', '1.4']
  /proc/net/ip_vs 里这个 Service 的条目(0050 是端口 80,调度器 rr = 轮询;Masq = NAT 转发;后端地址也是十六进制):
    TCP  0A6021E2:0050 rr
      -> 0AF40104:0050      Masq    1      0          0
      -> 0AF40103:0050      Masq    1      0          0
      -> 0AF40102:0050      Masq    1      0          0
  节点上多了一个 dummy 网卡 kube-ipvs0,上面挂着所有 Service 的 ClusterIP:3 个地址;类型:12: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default link/eth
  iptables nat 表里 KUBE-SEP 链数:0(ipvs 模式下 DNAT 不再靠 iptables 链)
  300 个新连接在三个后端的分布:[100, 100, 100](IPVS 默认调度器 rr 轮询,几乎完全均匀)
  再创建 300 个 Service(同一组后端),kube-ipvs0 网卡上新增的 ClusterIP 数(秒, 数量)的变化:[(1, 300)];全部 300 个到齐用了 1.2 秒
  最后一个 Service m299 从 apply 起到真的能访问(wget 返回后端主机名)用了 13.8 秒
  此时 iptables-save 总行数:85(规则数基本不随 Service 数增长)

Service web 在 /proc/net/ip_vs 里是 TCP 0A6021E2:0050 rr(0050 是端口 80 的十六进制,rr 是轮询调度器),下面三个真实服务器,转发方式 Masq(NAT)。节点上多了 dummy 网卡 kube-ipvs0,所有 ClusterIP 都挂在上面,让内核把它们当成本机地址;iptables 的 nat 表里 KUBE-SEP 链数是 0。300 个新连接在三个后端分成 100/100/100——轮询比概率抽签均匀得多。

nftables:一张表加 map

实测 · 本机执行输出
  集群 kx-nft:kube-proxy 配置 mode=nftables
  nft list tables:['table ip nat', 'table ip mangle', 'table ip filter', 'table ip6 mangle', 'table ip6 nat', 'table ip6 filter', 'table ip kube-proxy', 'table ip6 kube-proxy', 'table inet kindnet-network-policies']
  含 ClusterIP 10.96.45.66 的行:
    10.96.45.66 }
    10.96.45.66 . tcp . 80 : goto service-GVNVBQGN-k66/web/tcp/,
  和 web 有关的链:['service-GVNVBQGN-k66/web/tcp/']
    chain service-GVNVBQGN-k66/web/tcp/:meta l4proto tcp dnat ip to numgen random mod 3 map { 0 : 10.244.1.2 . 80, 1 : 10.244.1.3 . 80, 2 : 10.244.1.4
  300 个新连接在三个后端的分布:[94, 99, 107](随机)
  最后一个 Service m299 从 apply 起到真的能访问(wget 返回后端主机名)用了 15.0 秒
  再创建 300 个 Service,kube-proxy 表里新 Service 数(秒, 数量)的变化:[(0, 300)];全部 300 个到齐用了 0.1 秒;kube-proxy 表现在共 1799 行

nftables 模式的 kind 集群里多了 table ip kube-proxy。Service web 在入口的 map 里是 10.96.45.66 . tcp . 80 : goto service-GVNVBQGN-k66/web/tcp/(一次查表,不是逐条规则匹配),这条链里是 dnat ip to numgen random mod 3 map { 0 : 10.244.1.2 . 80, 1 : 10.244.1.3 . 80, 2 : 10.244.1.4 . 80 }:用随机数当下标去 map 里取后端。300 个连接分布 94/99/107,同样是随机。

规模与生效速度

实测 · 本机执行输出
  iptables 模式(集群 kx-main;最后一个 Service m299 从 apply 起到真的能访问用了 14.5 秒):新 Service 入口规则数(秒, 数量)的变化:[(0, 600)];全部 300 个到齐用了 0.1 秒;iptables-save 总行数 139 → 4639(+4500,约 15.0 行/Service,每个 Service 有 3 个后端)
  对比:ipvs 模式 iptables 总行数 85;nftables 模式 kube-proxy 表 1799 行(用 map,查找不是线性的)

同样再创建 300 个 Service(每个 3 个后端):ipvs 模式下 iptables-save 总行数仍是 85;nftables 的 kube-proxy 表共 1799 行;iptables 模式 iptables-save 总行数从 139 变成 4639,多了 4500 行,约 15 行/Service。但从 apply 到最后一个 Service m299 真的能访问,ipvs 13.8 秒、nftables 15.0 秒、iptables 14.5 秒——几乎一样,说明这个规模下瓶颈在控制面(300 个 Service 的 EndpointSlice 要一个个生成),而不是 kube-proxy 写规则。真正的差别在几千上万个 Service 时,本文没有测。

分步演示

ipvs 与 nftables
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。每种模式单独起一个两节点 kind 集群(1 控制面 + 1 worker,Kubernetes v1.37.0,networking.kubeProxyMode 取 ipvs / nftables),iptables 模式用 kx-main;读 /proc/net/ip_vs、ip addr、nft list、iptables-save 都在 worker 节点上;每个 Service 的后端是同一个 3 副本 busybox httpd;“可访问”用客户端 Pod 里的 wget 每 0.5 秒试一次;每种情形各一次(kube-proxy 在 v1.37 对 ipvs 模式已有弃用提示)
    • 没有验证:ipvs 的其他调度器(wlc、sh 等)与 ipvsadm 管理;ipvs 模式下 ipset 的使用;nftables 模式的 endpoint 链与 session affinity;几千个 Service 以上的规则同步耗时与 CPU;kube-proxy 参数 syncPeriod / minSyncPeriod 的影响;ipvs 弃用后的迁移;早期一次实验中 /proc/net/ip_vs 的条目数只数到一半左右(原因没查清,最终改用网卡地址数和实际访问验证)
    京ICP备2026067502号-1京公网安备11010502063487号