1. 问题现象与背景分析
上周五下午,我们生产环境的Kubernetes集群突然出现大规模网络连接异常。当时第一反应是回滚到上午的VMware快照,没想到恢复后问题更加严重——所有Pod之间的网络通信完全中断,kubectl命令虽然能执行但无法获取Pod日志,整个集群陷入瘫痪状态。
这个场景特别典型:当你在虚拟化环境中运行Kubernetes,特别是使用VMware的vSphere时,快照恢复可能会引发一系列隐蔽的网络问题。我花了整整6个小时才彻底解决,过程中发现这其实是个"复合型故障",涉及虚拟网卡MAC地址变更、kube-proxy的iptables规则失效、CNI插件状态不一致等多个层面的问题。
2. 故障排查全流程记录
2.1 第一阶段:基础网络检查
首先通过vSphere Client确认ESXi主机物理网卡状态正常,然后登录到Kubernetes节点执行基础检查:
bash复制# 检查节点IP配置
ip addr show | grep -A 5 "eth0"
# 测试节点间互通性
ping <其他节点IP>
# 检查默认路由
ip route show
发现所有节点的eth0网卡MAC地址与恢复快照前不同(关键发现!)。这是因为VMware默认配置下,恢复快照会为虚拟机生成新的MAC地址,而我们的Kubernetes网络配置中固定了旧MAC地址相关的设置。
2.2 第二阶段:Kubernetes组件诊断
检查核心组件日志发现异常:
bash复制journalctl -u kubelet --since "1 hour ago" | grep -i error
# 发现大量类似错误
networkPlugin cni failed to set up pod "nginx-deployment" network: failed to set bridge addr: "cni0" already has an IP address different from 10.244.0.1/24
这说明Flannel CNI插件检测到网络配置冲突。进一步检查发现:
- kube-proxy的iptables规则仍指向旧的Pod CIDR
- /var/lib/cni/目录下残留旧网络配置
- 节点上的kubelet和docker服务没有自动恢复
2.3 第三阶段:根本原因定位
通过对比快照前后的网络配置,确认三个关键变化点:
- 虚拟网卡标识变化:VMware自动生成的MAC地址改变,导致udev规则失效
- 网络命名空间污染:旧的veth设备未清理,与新创建的设备冲突
- 持久化数据不一致:etcd中存储的网络信息与节点实际配置不匹配
3. 完整解决方案
3.1 修复VMware网络配置
在vSphere中执行以下操作:
- 关闭所有Kubernetes节点虚拟机
- 编辑虚拟机设置 → 网络适配器 → 取消勾选"自动生成MAC地址"
- 手动设置为快照前的MAC地址(可从备份配置中获取)
- 启动虚拟机并验证MAC地址
3.2 清理Kubernetes网络残留
在每个节点执行:
bash复制# 清理CNI接口
sudo ip link delete cni0
sudo ip link delete flannel.1
# 重置iptables
sudo iptables -F
sudo iptables -t nat -F
# 删除网络命名空间残留
sudo rm -rf /var/lib/cni/*
sudo rm -rf /var/run/netns/*
3.3 重启集群组件
按顺序执行:
bash复制# 1. 重启docker
sudo systemctl restart docker
# 2. 清理kubelet
sudo systemctl stop kubelet
sudo rm -rf /var/lib/kubelet/*
sudo systemctl start kubelet
# 3. 强制删除所有Pod(会自动重建)
kubectl delete pods --all --grace-period=0 --force
4. 预防措施与最佳实践
4.1 VMware配置优化
- 固定MAC地址:对所有Kubernetes节点虚拟机禁用MAC地址自动生成
- 快照策略:创建快照前先优雅关闭节点,避免内存状态不一致
- 网络标签:为Kubernetes节点网络适配器添加专用标签
4.2 Kubernetes加固方案
yaml复制# 在kubelet配置中添加以下参数
--network-plugin=cni
--cni-conf-dir=/etc/cni/net.d
--cni-bin-dir=/opt/cni/bin
--hairpin-mode=hairpin-veth
4.3 自动化恢复脚本
创建紧急恢复脚本reset-k8s-network.sh:
bash复制#!/bin/bash
systemctl stop kubelet docker
ip link delete cni0 2>/dev/null
ip link delete flannel.1 2>/dev/null
iptables -F && iptables -t nat -F
rm -rf /var/lib/cni/* /var/run/netns/*
systemctl start docker kubelet
5. 深度技术解析
5.1 VMware快照原理的影响
VMware快照实际是磁盘状态的差分存储,但以下组件不会被快照保存:
- 虚拟硬件配置(包括MAC地址)
- 内存中的网络连接状态
- 主机物理网卡状态
这导致恢复时出现"半新半旧"的混合状态。
5.2 Kubernetes网络组件交互
恢复快照后各组件的时间线问题:
- kubelet先启动,尝试配置网络
- docker加载旧网络命名空间
- CNI插件检测到冲突
- kube-proxy加载过时的iptables规则
5.3 关键日志分析技巧
排查此类问题需要重点关注:
bash复制# kubelet网络相关错误
journalctl -u kubelet | grep -i "networkPlugin\|cni"
# docker网络初始化日志
docker logs <container_id> 2>&1 | grep -i "network"
# 内核网络事件
dmesg | grep -i "eth0\|veth"
6. 典型问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| Pod无法分配IP | CNI插件未启动 | 检查/opt/cni/bin是否存在 |
| 节点间网络不通 | MAC地址变化 | 固定VMware MAC地址 |
| iptables规则丢失 | kube-proxy故障 | 重启kube-proxy Pod |
| 服务ClusterIP不通 | IPVS模式问题 | 执行ipvsadm --clear |
7. 个人实战经验总结
-
快照不是备份:生产环境Kubernetes不能依赖VM快照作为恢复手段,必须配置etcd定期备份和Velero等专业工具
-
变更前记录状态:执行快照前务必记录以下信息:
bash复制ip addr show > network-state-before-snapshot.txt ip link show >> network-state-before-snapshot.txt iptables-save > iptables-before-snapshot.rules -
分阶段验证:恢复后先验证单节点网络,再逐步启动控制平面组件
-
监控关键指标:配置Prometheus监控以下指标:
- kubelet_network_plugin_errors_total
- kube_proxy_sync_proxy_rules_duration_seconds
这次故障给我的最大教训是:虚拟化环境中的Kubernetes需要特别关注网络持久化问题。现在我们在所有节点都配置了开机自检脚本,自动对比MAC地址和网络配置,提前发现问题。