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地址表转发到目标容器或外部网络。

排查要点:当容器间通信失败时,首先检查docker0网桥是否存在、veth pair是否成对出现、以及iptables FORWARD链是否允许转发。使用 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可以直接通信(扁平网络模型)。

CNI插件工作流程(ADD操作):
  1. kubelet调用CNI插件二进制文件,传入容器ID、网络命名空间路径、CNI配置等参数。
  2. 插件创建veth pair,一端放入Pod的网络命名空间,另一端连接到宿主机上的网桥或路由设备。
  3. 插件为Pod内的eth0接口分配IP地址(通常从集群CIDR中分配)。
  4. 插件添加必要的路由规则,确保Pod IP可达。
  5. 插件将结果(IP地址、MAC地址、DNS等)以JSON格式返回给kubelet。
CNI插件ADD操作流程 kubelet CNI配置 CNI插件 读取配置 调用插件(容器ID+命名空间) 创建veth pair 一端入Pod命名空间 IP地址分配 从集群CIDR获取 路由规则添加 确保Pod IP可达 返回JSON结果 IP/MAC/DNS/路由信息 kubelet更新Pod网络状态

2.3 Pod网络命名空间与通信机制

在Kubernetes中,每个Pod拥有一个独立的网络命名空间(netns)。Pod内的所有容器共享这个命名空间,因此它们可以通过localhost直接通信,共享同一个IP地址和端口空间。这是Pod设计的关键特性:容器间通信无需经过NAT或外部网络。

常见故障场景:如果Pod内的两个容器无法通过localhost通信,通常是因为它们被配置到了不同的网络命名空间(例如使用了 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规则
Pod网络命名空间与通信机制 PodA (Node1) 容器1 (app) 容器2 (sidecar) eth0: 10.1.1.2 PodB (Node2) 容器1 (app) 容器2 (sidecar) eth0: 10.1.2.3 跨节点通信路径 ① veth pair → 网桥 ② 路由表 → 宿主机eth0 ③ VXLAN隧道/BGP转发 ④ 目标节点网桥 → veth 同节点:网桥直接转发 同节点:网桥直接转发 关键排查点:路由表、ARP表、隧道端点、iptables FORWARD链 使用 ip route、arp -n、bridge fdb show、iptables -L FORWARD 诊断

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
生产建议:在自动化流水线中,将上述脚本集成到PostSync Hook中,每次蓝绿发布后自动执行网络健康检查。如果检测到网络命名空间缺失或路由异常,立即触发回滚并输出诊断日志。