【dive-into-k8s】用 Kind 手撸 CNI,从 CrashLoop 到 VXLAN 抓包解剖
周末,我在 Manjaro 上利用 kind 从零构建了一个“无网络”集群,手动排查了内核模块缺失、CNI 插件丢失等硬核故障,并最终通过 tcpdump 亲眼见证了 VXLAN 的封包过程。这篇文章记录了全过程。
在云原生领域,CNI (Container Network Interface) 往往是很多开发者的知识盲区。我们习惯了 kubectl apply -f flannel.yaml 一键梭哈,却很少探究底层发生了什么。
特别是对于致力转向 AI Infra 的工程师来说,高性能网络是分布式训练的命脉。如果连基础的 Overlay 网络开销在哪里都不知道,就更谈不上后续的 RDMA 或 eBPF 优化了。
一、 环境准备:制造“犯罪现场”
为了深入理解,我没有使用默认配置,而是强行禁用了 Kind 的默认 CNI,模拟一个只有骨架没有神经的“裸”集群。
环境: Manjaro Linux + Docker + Kind
kind-config.yaml:
| |
启动集群后,正如预期,节点状态为 NotReady。
进入节点内部查看 ip addr,只有 lo 和 eth0,完全没有 cni0 或 flannel.1 这样的网桥接口。此时的 Kubernetes 就像一个植物人,有心跳(Kubelet 在跑)但无法动弹(Pod 无法通信)。
二、 步步惊心的 Debug 之路
我选择安装经典的 Flannel 插件来“激活”网络,但过程并非一帆风顺。
1. 幽灵 Pod 与命名空间陷阱
执行安装命令后,习惯性查看 kube-system 命名空间,结果空空如也。
| |
排查: 检查 DaemonSet 发现 DESIRED 副本数正常。原来新版 Flannel 为了隔离性,已经将自己迁移到了独立的 kube-flannel 命名空间。
教训: 排查资源丢失时,请务必使用 kubectl get pods -A。
2. 内核的拒绝:Missing br_netfilter
找到 Pod 后,发现它们全部处于 CrashLoopBackOff 状态。查看日志,捕获到了核心报错:
| |
深度解析:
这是 Linux 内核与 K8s 网络的经典冲突。Linux Bridge 默认工作在二层(数据链路层),不经过 iptables。而 K8s 的 Service (ClusterIP) 强依赖 iptables 做 NAT 转发。br_netfilter 模块的作用就是架起一座桥,强制经过网桥的流量进入 iptables 处理。
解决方案(在宿主机 Manjaro 上执行):
| |
因为 Kind 容器共享宿主机内核,宿主机加载模块后,容器内立即生效。
3. 消失的施工队:CNI Chaining 故障
Flannel 终于 Running 了,但我部署的测试 Pod (Nginx) 却一直卡在 ContainerCreating。
kubectl describe pod 揭示了新的问题:
| |
深度解析:
这里涉及到了 CNI 链式调用 (Chaining)。Flannel 只是“项目经理”,负责分配网段(IPAM)和同步路由。真正干脏活累活(创建 cni0 网桥、连接 veth pair)的是 CNI 标准库中的 Bridge 插件。Kind 的极简节点镜像中并没有预置这些基础二进制文件。
解决方案: 我们需要手动“空投”这些插件进去。
- 下载官方
cni-plugins-linux-amd64包。 - 将解压后的
bridge、loopback等二进制文件复制到 Kind 节点的/opt/cni/bin/目录。
| |
这波操作后,所有 Pod 瞬间变绿(Running)。查看节点内部,subnet.env 成功生成,网络打通。
三、 终极解剖:Tcpdump 实战 Overlay 网络
网络通了只是开始,作为一个 AI Infra 预备役,必须看清数据包到底长什么样。我在 Control-plane 节点抓包,观察跨节点访问流量。
实验拓扑:
- Client: Netshoot Pod (在 Control-plane 节点)
- Server: Nginx Pod (在 Worker 节点)
抓包命令: 监听宿主机网卡的 UDP 8472 端口(VXLAN 标准端口)。
| |
抓包结果分析:
| |
硬核结论:
通过 -v 参数,清晰地看到了“包中包”结构。
- 外层 (Underlay):节点 IP 之间的 UDP 通信,目标端口 8472。
- 内层 (Overlay):Pod IP 之间的 ICMP 通信。
- 性能税 (Tax):外层包长 134 字节,内层包长 84 字节。这意味着每个数据包都有 50 字节 的封装开销。
四、 总结
这次实战不仅修复了 CrashLoop,更重要的是量化了 Overlay 网络的成本。
在 Web 场景下,50 字节微不足道。但在 AI 大模型训练(如 AllReduce)场景下,海量梯度同步对延迟极度敏感。这 50 字节的封包/解包开销以及 CPU 上下文切换,可能就是制约 GPU 集群性能的瓶颈。
这也是为什么在高端 AI Infra 中,我们往往弃用 VXLAN,转而探索 HostNetwork、MacVLAN 甚至基于 eBPF 的 Cilium 方案,以追求极致的零损耗网络。
Next Step: 下一步,我将把 Flannel 替换为 Cilium,并尝试使用 Hubble 可视化观察网络拓扑。