bigywater.tech
Kubernetes · 76

CNI:Pod IP 怎么分配,veth 怎么连

Pod IP 是谁分配的?CNI 到底做了什么?veth 在哪里?为什么删除 Pod 后 IP 没有马上被复用?这篇在 kind 节点里读 CNI 配置、IPAM 记账文件、nsenter 进 Pod 的网络命名空间看 veth 和路由,把 CNI 的每一步现场对出来。

/24 每节点
node.spec.podCIDR 给每个节点一段 /24,host-local 只在本节点范围内分配
10.244.1.190 不回头
释放后新建的 Pod 拿到的是 .192,往后分配,不立即复用
2.3 秒
Pod 对象消失后到路由和 veth 被清掉的延迟

CNI 配置与 IPAM

实测 · 本机执行输出
  节点 worker 上的 /etc/cni/net.d/10-kindnet.conflist:name=kindnet;插件链 ['ptp', 'portmap']
  第一个插件 ptp:ipam=host-local,dataDir=/run/cni-ipam-state,ranges=[[{'subnet': '10.244.1.0/24'}]],routes=[{'dst': '0.0.0.0/0'}],mtu=65535
  节点 control-plane:spec.podCIDR=10.244.0.0/24;  这个节点上 CNI 配置里的 subnet=10.244.0.0/24
  节点 worker:spec.podCIDR=10.244.1.0/24;  这个节点上 CNI 配置里的 subnet=10.244.1.0/24
  节点 worker2:spec.podCIDR=10.244.2.0/24;  这个节点上 CNI 配置里的 subnet=10.244.2.0/24

节点 worker 上 /etc/cni/net.d/10-kindnet.conflist 的插件链是 ptp 和 portmap。ptp 的 ipam 是 host-local,dataDir 是 /run/cni-ipam-state,ranges 里的 subnet 就是这个节点的 spec.podCIDR(control-plane 10.244.0.0/24、worker 10.244.1.0/24、worker2 10.244.2.0/24),routes 是默认路由,mtu 65535。每个节点自己管自己那一段,不需要和别的节点协调。

host-local 怎么记账

实测 · 本机执行输出
  worker 上 3 个新 Pod 的 IP:['10.244.1.189', '10.244.1.190', '10.244.1.191'](都在 10.244.1.0/24 里,从上一个分配的地址继续往后)
  /run/cni-ipam-state/kindnet/ 里每个已分配的 IP 一个文件,外加 last_reserved_ip.0 记录上次分配到哪:['10.244.1.189', '10.244.1.190', '10.244.1.191']
  文件 10.244.1.189 的内容(记录占用它的沙箱 ID 前 12 位):f4042ba0a12b…;last_reserved_ip.0=10.244.1.191
  删除 Pod b(10.244.1.190):API 对象消失后又过了 2.2 秒,IPAM 里这个 IP 的文件才被删掉(CNI 的 DEL 在容器停止之后才执行)
  新建 Pod d 的 IP:10.244.1.192(没有立刻回收 10.244.1.190,而是继续往后分配;地址用完一圈后才会复用)

worker 上新建 3 个 Pod,IP 是 10.244.1.189、.190、.191,从上一次分配的地址继续往后。/run/cni-ipam-state/kindnet/ 下每个已分配的 IP 一个文件(内容是占用它的沙箱 ID),再加 last_reserved_ip.0 记着上次分到哪(.191)。删除 Pod b(.190)后,API 对象消失又过了 2.2 秒这个文件才被删——CNI 的 DEL 要等容器停止之后才执行;随后新建 Pod d 得到 10.244.1.192,没有回头用刚释放的 .190,地址要用完一圈才会复用。

一对 veth

实测 · 本机执行输出
  Pod a 的网络命名空间里:
    eth0@if704 UP 10.244.1.189/24 fe80::345b:27ff:fe4a:97ab/64
    default via 10.244.1.1 dev eth0
    10.244.1.0/24 via 10.244.1.1 dev eth0 src 10.244.1.189
    10.244.1.1 dev eth0 scope link src 10.244.1.189
    11: eth0@if704: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65535 qdisc noqueue state UP mode DEFAULT group default qlen 1000
     link/ether 36:5b:27:4a:97:ab brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0 allmulti 0 minmtu 68 maxmtu 65535
     veth addrgenmode eui64 numtxqueues 10 numrxqueues 10 gso_max_size 65536 gso_max_segs 65535 tso_max_size 524280 tso_max_segs 65535 gro_max_size 65536 
  Pod 里 eth0 的 ifindex=11,它的对端是 ifindex=704;节点上 ifindex=704 的网卡:veth25040d0e@if11(名字里的 @if11 又指回 Pod 里的 eth0,两头互指)
  节点上通往这个 Pod 的路由:10.244.1.189 dev veth25040d0e scope host(/32 主机路由,直接指向它的 veth veth25040d0e,没有网桥)
  worker 上 veth 数 4;就绪的 Pod 沙箱数 6(其中 hostNetwork 的 Pod 没有 veth)

用 nsenter 进 Pod a 的网络命名空间:eth0@if704,地址 10.244.1.189/24,默认路由 via 10.244.1.1。节点上 ifindex 704 的网卡是 veth25040d0e@if11,名字里的 @if11 又指回 Pod 里 eth0 的 ifindex 11:一对 veth 两头互指。节点上通往这个 Pod 的路由是 10.244.1.189 dev veth25040d0e scope host——一条 /32 主机路由直接指向 veth,没有网桥。

撤销

实测 · 本机执行输出
  Pod d(10.244.1.192)存在时节点上到它的路由 1 条
  Pod d 的 API 对象消失后又过 2.3 秒,到它的路由才没有(CNI DEL 之后 veth 被删,路由跟着消失);veth 数 4 → 3;IPAM 里 10.244.1.192 的文件已释放

删除 Pod d 后,API 对象消失又过了 2.3 秒,节点上到 10.244.1.192 的路由才没有;veth 数 4 → 3,IPAM 里的记录释放。网络配置随沙箱销毁(CNI DEL)而撤销,不是随 API 对象删除而立即撤销。

分步演示

CNI
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0),CNI 是 kind 默认的 kindnet(ptp + host-local + portmap);在 worker 节点用 docker exec 读 /etc/cni/net.d、/run/cni-ipam-state,用 crictl inspectp + nsenter 进入 Pod 的网络命名空间;Pod 用 nodeName 固定在 worker 上;删除延迟是 0.3 秒间隔轮询,单次测量;每种情形各一次
    • 没有验证:Calico / Cilium / Flannel 等其他 CNI 的 IPAM 与数据路径;CNI 插件链里 portmap 对 hostPort 的实现;IPv6 / 双栈;podCIDR 用尽后的行为;kubelet 调用 CNI 的错误处理与重试;containerd 的 CNI 配置目录与二进制目录的选择
    京ICP备2026067502号-1京公网安备11010502063487号