Pod IP 是谁分配的?CNI 到底做了什么?veth 在哪里?为什么删除 Pod 后 IP 没有马上被复用?这篇在 kind 节点里读 CNI 配置、IPAM 记账文件、nsenter 进 Pod 的网络命名空间看 veth 和路由,把 CNI 的每一步现场对出来。
节点 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。每个节点自己管自己那一段,不需要和别的节点协调。
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,地址要用完一圈才会复用。
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 对象删除而立即撤销。