2. 容器网络基础:Docker网络模型、CNI插件原理、Pod网络命名空间与通信机制
在蓝绿发布与流量切换场景中,网络故障是最常见且最难定位的问题类型。理解容器网络的分层模型、命名空间隔离机制以及CNI插件的编排原理,是进行自动化故障排查的根基。本章从Docker网络模型出发,逐步深入到Kubernetes的Pod网络通信核心。
2.1 Docker网络模型:单机容器通信基础
Docker提供了四种内置网络驱动,每种驱动对应不同的隔离级别与通信范围。在生产环境中,bridge和overlay是最常用的两种模式。
| 网络模式 | 驱动类型 | 通信范围 | 典型场景 |
|---|---|---|---|
| bridge | 桥接 | 同主机容器间 | 单机容器互联 |
| host | 主机 | 容器与主机共享网络栈 | 性能敏感型应用 |
| none | 空 | 无网络接口 | 自定义网络栈 |
| overlay | 覆盖 | 跨主机容器间 | Swarm/K8s集群 |
Docker bridge网络的核心原理是通过Linux内核的veth pair(虚拟以太网对)将容器网络命名空间连接到宿主机网桥(docker0)。每个容器启动时,Docker会创建一对veth接口:一端放入容器命名空间(eth0),另一端连接到docker0网桥。容器内的数据包通过veth pair到达网桥,再由网桥根据MAC地址表转发到目标容器或外部网络。
brctl show 和 ip link 命令快速定位。
2.2 CNI插件原理:Kubernetes网络标准化接口
Kubernetes没有内置网络实现,而是通过CNI(Container Network Interface)标准来对接第三方网络插件。CNI定义了一组规范:插件必须实现 ADD、DEL、CHECK 三个操作,并通过JSON格式的配置文件与kubelet交互。
常见的CNI插件包括Calico(基于BGP路由)、Flannel(基于VXLAN覆盖网络)、Cilium(基于eBPF)等。它们的核心职责一致:为每个Pod分配唯一的IP地址,并确保跨节点Pod可以直接通信(扁平网络模型)。
- kubelet调用CNI插件二进制文件,传入容器ID、网络命名空间路径、CNI配置等参数。
- 插件创建veth pair,一端放入Pod的网络命名空间,另一端连接到宿主机上的网桥或路由设备。
- 插件为Pod内的eth0接口分配IP地址(通常从集群CIDR中分配)。
- 插件添加必要的路由规则,确保Pod IP可达。
- 插件将结果(IP地址、MAC地址、DNS等)以JSON格式返回给kubelet。
2.3 Pod网络命名空间与通信机制
在Kubernetes中,每个Pod拥有一个独立的网络命名空间(netns)。Pod内的所有容器共享这个命名空间,因此它们可以通过localhost直接通信,共享同一个IP地址和端口空间。这是Pod设计的关键特性:容器间通信无需经过NAT或外部网络。
shareProcessNamespace: false 且未正确设置共享网络)。排查时进入Pod执行 ip netns identify 或检查 /proc/1/ns/net 的inode号是否一致。
2.3.1 Pod内部通信:共享网络栈
Pod内的pause容器(基础设施容器)负责持有网络命名空间。业务容器启动时通过 --network=container:pause 加入该命名空间。这种设计带来的好处:
- IP唯一性:整个Pod只有一个IP地址,简化了服务发现和负载均衡。
- 端口共享:容器间可以通过localhost互相访问,性能高且无需序列化。
- 生命周期管理:pause容器先于业务容器启动,后于业务容器销毁,确保网络资源稳定。
2.3.2 Pod间通信:扁平三层网络
Kubernetes要求所有Pod之间可以不通过NAT直接通信,无论它们是否在同一节点。这被称为扁平网络模型。实现这一模型的核心机制包括:
| 通信路径 | 数据流向 | 关键组件 |
|---|---|---|
| 同节点Pod间 | PodA → veth → 网桥 → veth → PodB | cni0/docker0网桥、ARP表 |
| 跨节点Pod间 | PodA → veth → 网桥 → 路由 → 宿主机eth0 → 隧道/路由 → 目标节点 → 网桥 → PodB | 路由表、VXLAN隧道/BGP、宿主机网络 |
| Pod访问Service | Pod → Service ClusterIP → iptables/IPVS → 后端Pod | kube-proxy、iptables/IPVS规则 |
2.4 蓝绿发布场景中的网络故障高发点
在蓝绿发布过程中,网络层面的故障通常集中在以下三个环节:
- Service与Pod的标签选择器不匹配:新版本Pod的标签未正确设置,导致Service无法将流量路由到新Pod。排查时使用
kubectl get endpoints检查Endpoint是否更新。 - CNI插件IP池耗尽:频繁发布导致大量Pod创建和销毁,IP地址回收不及时,新Pod无法分配到IP。排查时检查CNI插件的IPAM状态。
- 网络策略(NetworkPolicy)阻断流量:新版本Pod的标签变化后,原有的NetworkPolicy未适配,导致Pod间或Pod与外部通信失败。排查时使用
kubectl describe networkpolicy确认规则。
2.5 自动化排查脚本基础:网络命名空间探测
在自动化故障排查中,第一步通常是探测Pod的网络命名空间状态。以下是一个基础的探测脚本片段,用于检查Pod的网络连通性:
#!/bin/bash
# 网络命名空间探测脚本 - 用于蓝绿发布故障排查
POD_NAME=$1
NAMESPACE=$2
# 获取Pod的UID和网络命名空间路径
POD_UID=$(kubectl get pod $POD_NAME -n $NAMESPACE -o jsonpath='{.metadata.uid}')
NETNS_PATH="/var/run/netns/cni-${POD_UID}"
# 检查网络命名空间是否存在
if [ -f "$NETNS_PATH" ]; then
echo "[OK] 网络命名空间存在: $NETNS_PATH"
else
echo "[FAIL] 网络命名空间不存在,CNI插件可能未正确执行ADD操作"
exit 1
fi
# 进入命名空间检查网络接口
nsenter --net=$NETNS_PATH ip addr show eth0 2>/dev/null
if [ $? -eq 0 ]; then
echo "[OK] Pod网络接口正常"
else
echo "[FAIL] Pod网络接口异常"
fi
# 检查默认路由
nsenter --net=$NETNS_PATH ip route show default