系列导航
本系列从 Pod 网络连通入手,逐步展开到 K8s 网络全景。
① 概念 → ② Flannel → ③ Calico → ④ 流量路径 → ⑤ Cilium → ⑥ 对比 → ⑦ 排障 ‖ ⑧ 开发 → ⑨ 多网卡 → ⑩ AI 演进
| 顺序 | 文章 | 定位 |
|---|---|---|
| ① | 概念与入门 | 基础——主机网络、Docker 网络、CNI 标准、方案分类树 |
| ② | 本篇 - Flannel 详解 | CNI 实现——Overlay(UDP/VXLAN)+ Underlay(HostGW)与抓包 |
| ③ | Calico 详解 | CNI 实现——Overlay(VXLAN/IPIP)+ Underlay(BGP)+ NetworkPolicy |
| ④ | 流量路径全解析 | 全貌——Pod/Service/Ingress/Egress,揭示 CNI 的边界 |
| ⑤ | Cilium 详解(超CNI) | 超 CNI——eBPF 数据平面(Service + NetworkPolicy)+ CNI 连通(VXLAN/BGP) |
| ⑥ | 插件对比与选型 | 选型——5 插件横向对比 + 决策树 |
| ⑦ | 排障思路与常用命令 | 运维——工具链 + 场景排查 + 性能 |
| — | 核心路径 ↑ | 扩展展望 ↓ |
| ⑧ | CNI 插件开发指南 | 扩展——基于 CNI 规范开发自定义插件 |
| ⑨ | 多网卡方案详解 | 进阶——Multus + SR-IOV/ipvlan 多网口实战 |
| ⑩ | AI 时代网络演进 | 展望——GPU 网络、eBPF 加速、未来方向 |
Flannel 由 CoreOS 开发,是 k8s 最成熟的开源 CNI 插件之一,通过三层网络把各节点的 Pod 子网连成一个跨节点的内部网络,每个节点分配一个子网。
1. Flannel架构
1.1 组件
flanneld —— 每个节点上的核心进程,作为 DaemonSet 部署,负责子网划分、子网租赁管理,使用 Etcd 或 K8S API 存储状态。
cni0 —— Linux 网桥,由 bridge CNI 插件创建,对应 Docker 单机环境的 docker0。每个 Pod 的 veth pair 对端插入 cni0,降级为网桥端口。同节点 Pod 间通信走 CAM 表二层转发。
后端(Backend) —— 负责跨节点报文的具体转发方式。Flannel 提供三种后端:UDP(用户态 Overlay)、VXLAN(内核态 Overlay)、Host-GW(路由模式)。
1.2 原理
每个节点从全局子网池中租赁一个子网段(如 10.244.1.0/24),节点内 Pod 从该段分配 IP。跨节点 Pod 通信时,转发路径为:
Pod eth0 → veth pair → cni0 网桥 → 宿主机路由 → 后端封装/转发 → 对端宿主机 → cni0 → veth pair → 目标 Pod
与 Calico 的关键区别在数据平面:Flannel 的 veth pair 对端必须插入 cni0 网桥——先经二层 CAM 转发(网桥层),再进宿主机路由表做三层转发(路由层),即「网桥+路由」两层。Calico 的 veth 对端不插网桥、直接对接宿主机路由表,是「纯路由」单层结构(Calico 篇展开)。
注意:Calico 的所有模式都不用网桥——包括 VXLAN 模式,它用 per-pod 路由 + VTEP 设备(
vxlan.calico)做 Overlay,而不是把 veth 插进网桥。「用了 Overlay 就一定有网桥」是常见误区,详见 Calico 篇。
1.3 IPAM:子网租赁与 Pod IP 分配
Flannel 的 IP 管理分两层,对应「谁决定子网」和「谁分配具体 IP」:
第一层:子网租赁(flanneld)
flanneld 从全局子网池(Network 配置项,默认 10.244.0.0/16)为每个节点租赁一个子网段(如 10.244.1.0/24),租约写入 Etcd 或 K8S API,节点下线后释放归还池子。
第二层:Pod IP 分配(host-local CNI 插件)
节点内分配 Pod IP 的是 CNI 标准的 host-local IPAM 插件。flanneld 把本节点租赁到的子网写进 CNI 配置,host-local 读取后从子网中按序分配 IP(10.244.1.2、10.244.1.3…),并把已分配 IP 记录在本地目录(/var/lib/cni/networks/<network>)。
两者分工:flanneld 管「哪个节点用哪个子网」,host-local 管「子网里哪个 IP 给哪个 Pod」。
2. Flannel后端模式
Flannel 解决的核心问题:跨节点 Pod 发送 IP 包时,原始 Pod 报文如何到达对端节点? 三种后端给出三种答案:
| 模式 | 分类 | 通路 | 封装位置 | 性能 | 前提条件 |
|---|---|---|---|---|---|
| UDP | Overlay(L3) | flanneld 进程间 UDP 通信 + TUN 设备 flannel0 | 用户态 | 最差(3次状态切换) | 无 |
| VXLAN | Overlay(L2) | 内核态 VTEP (flannel.1) + VXLAN 隧道 + FDB 转发 | 内核态 | 良好(~50字节开销) | 内核支持 VXLAN |
| Host-GW | Underlay(路由) | 静态路由,flanneld 直接修改宿主机路由表 | 无封装 | 最高(裸机性能) | 所有节点 L2 互通 |
Flannel 的三种后端按转发方式分为两类:Overlay 封装(UDP、VXLAN)和 Underlay 路由(Host-GW)。
2.1 Overlay: UDP 模式
通路:flanneld 进程间 UDP 通信 + TUN 设备 flannel0——各节点 flanneld 组成 Overlay 网络,用户态封包解包,实现最简单,性能最差。
封装结构:|HostMAC|HostIP|UDP|内层IP|Data|,IP 头(20B)+ UDP 头(8B)= 28B 开销。
2.1.1 组件概念
flannel0:TUN 设备
flannel0 是一个 TUN 设备(三层虚拟网络设备),在内核和应用程序(flanneld 进程)之间传递 IP 包:
| 方向 | 流向 | 行为 |
|---|---|---|
| 宿主机 → flannel0 | 内核态 → 用户态 | 内核态 IP 包交给创建该设备的应用程序(flanneld 进程) |
| flanneld → flannel0 | 用户态 → 内核态 | flanneld 进程写入的 IP 包,出现在宿主机网络栈,按路由表流转 |
2.1.2 封装流程
五段流程
| |
1. S.容器 → S.cni0
1.1 容器内,默认路由,即 cni0 的 IP == 网关 IP,通过容器 eth0 发出,目标 IP = 目的容器 IP,目标 MAC = cni0.MAC;
1.2 容器 eth0 → veth-pair → cni0 端口 vethxx;
1.3 cni0 发现目标 MAC == 自身 MAC,发往 S.宿主机网络栈。
2. S.cni0 → S.flanneld 进程
2.1 到达 S.宿主机网络栈后,根据路由(flanneld 维护),目标 IP(目的容器 IP) ∈ Overlay 网段,发往 flannel0 设备(TUN);
2.2 根据 flannel0 设备的 TUN 特性,IP 包进入 flanneld 进程(注意,内核此时会剥离原始报文的 L2 头,将 IP 报文发给 flannel0)。
3. S.flanneld → D.flanneld
3.1 S.flanneld 进程,根据目的容器 IP 结合 Etcd 中节点-子网对应关系,获得目的宿主机 IP,目的端口 = 8285;
3.2 经宿主机网络,到达目的宿主机 UDP 进程——D.flanneld 进程。(注意:进入目标主机内核后,会重新 ARP 缓存或 ARP 请求,根据目标 IP 取得目标 MAC,再封装二层头。此行为属于步骤 4.3。)
4. D.flanneld → D.cni0
4.1 D.flanneld 进程收到数据时,D.宿主机网络栈已剥离 L2-L4 协议头,得到原始报文(L3 层报文,目标 IP = 目的容器 IP。跟 S.flanneld 收到的一模一样);
4.2 D.flanneld 进程,将 IP 包发往 D.flannel0,IP 报文进入 D.宿主机网络栈;
4.3 D.宿主机网络栈,根据路由(flanneld 维护),目标 IP(目的容器 IP) ∈ 当前节点子网,出设备 = D.cni0。
cni0 是一个网桥(二层设备),要通过它发送,必须封装以太网帧头。D.宿主机网络栈封装 L2 帧头,通过 ARP 请求或 ARP 缓存获取目的容器 MAC,并封装。
5. D.cni0 → D.容器
5.1 cni0,根据目的容器 MAC,查 CAM 表,转发至指定端口 veth;
5.2 端口 veth → veth-pair → 进入目的容器 eth0。
2.1.3 性能分析
为什么性能差?三次内核态↔用户态切换
发送端:
第一次:容器进程 → 容器 eth0 用户态 → 内核态
之后 eth0→vethxx→cni0→flannel0 一直在内核态
第二次:flannel0 → flanneld 进程 内核态 → 用户态 ← TUN 特性
第三次:flanneld 进程 → 宿主机 eth0 用户态 → 内核态2.2 Overlay: VXLAN 模式
通路:内核态 VTEP 设备 flannel.1 + VXLAN 隧道 + FDB 转发表,封装/解包全在内核中完成。
封包格式:|HostMAC|HostIP|UDP|VXLAN|内层MAC|内层IP|Data|,总计 50B 开销(外层 IP 头 20 + UDP 头 8 + VXLAN 头 8 + 内层 MAC 14)。
VXLAN (Virtual Extensible LAN) 是 Linux 内核原生支持的 Overlay 协议,采用内核态标准协议,所有封装/解包在内核中完成,实际传输速度比 UDP 模式快许多。内核态 VTEP 设备 flannel.1 使用 UDP 端口 8472(VXLAN)做封装/解封,对端节点用随机端口连接。
VNI (VXLAN Network Identifier): Flannel 默认使用 VNI 1。同一 VNI 内的节点属于同一个 L2 广播域。
2.2.1 组件概念
flannel.1 = VTEP
flannel.1 是一个 VTEP(VXLAN Tunnel End Point)设备,工作在内核态,负责 VXLAN 封装和解封。
与普通网桥(cni0)的区别:
| 特性 | 普通网桥(cni0) | VTEP(flannel.1) |
|---|---|---|
| 转发表 | CAM 表(端口 ↔ MAC) | FDB 表(远端 VTEP MAC ↔ 远端宿主机 IP) |
| 是否记录 IP | 否 | 是,FDB 记录远端宿主机 IP |
| 封装能力 | 无封装,纯二层转发 | 内核态 VXLAN 封装/解封 |
三层表
flanneld 进程在每个节点预置三类表项,构成完整的数据平面:
| 表 | 内容 | 作用 | 查看命令 |
|---|---|---|---|
| 路由表 | 远端子网 → flannel.1,网关 = 远端 VTEP IP | 将跨节点 Pod 流量引向 VTEP 设备 | ip route |
| ARP 表 | 远端 VTEP IP → 远端 VTEP MAC | VTEP 间邻居发现,回答"对端 VTEP 的 MAC 是什么" | ip neigh show dev flannel.1 |
| FDB 表 | 远端 VTEP MAC → 远端宿主机物理 IP | 回答"对端 VTEP 在哪台宿主机上" | bridge fdb show dev flannel.1 |
| |
flannel.1 虚拟网卡),无需像 UDP 模式那样经过用户态 flanneld 进程,性能显著优于 UDP 方案。2.2.2 封装流程
完整封装流程
以源容器 → 目的容器为例:
步骤1:源容器发出 IP 包 S.容器 eth0 → veth pair → S.宿主机 cni0 网桥 → 路由表匹配:D.容器IP ∈ 远端子网 步骤2:路由引向 VTEP 路由规则(flanneld 预置): 10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink → IP 包发往 S.flannel.1,下一跳 = 远端 VTEP IP 步骤3:VTEP 内层二层封装 flannel.1 查 ARP 表:远端 VTEP IP → 远端 VTEP MAC 封装内层以太网帧头:S.VTEP.MAC + D.VTEP.MAC 步骤4:VTEP 封 VXLAN 头 添加 VNI = 1,形成 VXLAN 报文 步骤5:VTEP 封外层 UDP+IP 头 查 FDB 表:D.VTEP.MAC → D.宿主机.IP 源 IP = S.宿主机.IP, 目标 IP = D.宿主机.IP 目标端口 = 8472 步骤6:宿主机二层发出 查路由表/ARP,封装外层以太网帧(D.宿主机.MAC),从 eth0 发出 步骤7:目的宿主机解封装 D.宿主机 eth0 → 内核依次解外层 MAC/IP/UDP → 识别 VXLAN 端口 8472 → 根据 VNI=1 交给 flannel.1 步骤8:VTEP 剥离内层头 flannel.1 剥离 VTEP 内层 MAC 头、VXLAN 头,还原原始 IP 包 步骤9:路由到目标容器 查路由表,目标 IP ∈ 本机 Pod 子网 → 走 cni0 → ARP 获取容器 MAC → 封装二层头 → cni0 CAM 转发 → veth pair → D.容器 eth0
2.2.3 抓包验证
抓包验证
如下面一条抓包数据所示——源 192.168.1.215 节点的 pod [10.42.0.0] 访问目的 192.168.1.216 节点的 pod [10.42.1.7] 的 443 端口,抓源主机 enp0s3 设备的 UDP 包:
| |
192.168.1.215.38381 > 192.168.1.216.8472:外层 UDP 包,源端口 38381,目标端口 8472(VXLAN 协议端口)f2:60:ca:96:7f:1f > 4a:02:36:26:f9:c1:外层以太网帧,源/目标 MAC 为两台宿主机enp0s3网卡的 MAC10.42.0.0.10384 > 10.42.1.7.443:内层 TCP 包,这是 Pod 之间真实的通信——源 IP10.42.0.0,目标 IP10.42.1.7
注:抓包里的
OTV是 tcpdump 的误识别——VXLAN 与 Cisco OTV 都默认用 UDP 8472 端口,老版本 tcpdump 会把 8472 上的 VXLAN 报文显示成 OTV,实际封装是 VXLAN。
2.3 Underlay: Host-GW 模式
cni0 网桥——flanneld 将 Pod 子网路由写入宿主机路由表,跨节点无任何封装,性能等于裸机网络。2.3.1 组件概念
与前两种 Overlay 模式不同,Host-GW 采用主机路由方案——去掉的是隧道封装(没有 flannel.1、没有 flannel0),改走宿主机普通三层路由。既然跨节点不通是因为节点间缺少 Pod 子网的路由信息,而 Flannel 知道这些信息,就直接把它刷到宿主机路由表上。
注意:cni0 网桥依然存在。 veth 对端仍然插在 cni0 上,同节点 Pod 通信仍走网桥二层转发(CAM 表),与 Overlay 模式完全一致。Host-GW 删掉的只是跨节点的隧道设备,网桥和容器接入方式都没变。
跨节点通信靠路由:flanneld 在每台宿主机路由表维护「其他节点 Pod 子网 → 下一跳 = 目标节点主机 IP」的静态路由(如 10.244.2.0/24 via 192.168.1.2)。包到达目的节点后,由目的节点通过本机 cni0 直连路由进入网桥、再转给容器(完整路径见 2.3.3)。
Host-GW 没有 Overlay 的装包解包操作,完全是普通网络路由机制,性能接近裸机网络。
然而,Flannel 只能修改宿主机的路由表,一旦节点间隔了其他三层设备(如路由器),该设备没有 Pod 子网的路由,会把包丢弃或错误转发。因此 Host-GW 要求所有节点在同一个 L2 广播域内——下一跳(目标节点)必须 on-link 直连可达。
2.3.2 主要流程
工作原理: 1. 每个节点的 Pod 子网在 Etcd 注册,flanneld 感知全局子网 2. flanneld 在每台宿主机路由表写入到其他节点子网的静态路由,下一跳 = 目标节点主机 IP 3. 同节点通信:Pod → veth → cni0 网桥 → CAM 转发 → 目标 Pod(不进路由表) 4. 跨节点发送:源 Pod → veth → cni0 → 匹配远端 via 路由 → 经 eth0 发往目标节点 5. 目的节点接收:剥 L2 → 匹配本机直连路由 /24 dev cni0 → 进网桥 → CAM 转发 → 目标 Pod
2.3.3 路由验证
假设两个节点:
| |
flanneld 在节点1 的路由表中写入:
| |
flanneld 在节点2 的路由表中写入:
| |
节点1 的 Pod(10.244.1.5)访问节点2 的 Pod(10.244.2.8),完整路径如下:
| |
整条路径无任何隧道封装,IP 头从源 Pod 到目的 Pod 全程不变,每跳只换 L2 帧的 MAC(via 机制见 2.2.2 的知识科普)。
同节点通信更简单:10.244.1.5 访问本机 10.244.1.6,包到 cni0 后查 CAM 直接转到同一网桥上的 veth,完全不进路由表。
3. 流量加密
Flannel 的 VXLAN/UDP 封装默认不加密,跨不可信网络(如公网)时报文可被窃听。Flannel 提供两种加密后端:
- WireGuard: 当前推荐方案,内核态加密,性能开销小。每个节点配置一对密钥,节点间流量在 VXLAN 封装之外再套一层 WireGuard 隧道。
- IPSec: 早期方案,用 strongSwan 在节点间建立 IPSec 隧道,已标记 deprecated,性能差,不建议新部署。
加密只作用于跨节点流量;同节点 Pod 通信走 cni0 网桥、不离开宿主机,无需加密。
4. 总结
| 维度 | UDP | VXLAN | Host-GW |
|---|---|---|---|
| 封装开销 | 28B | 50B | 0 |
| 封装位置 | 用户态 | 内核态 | 无封装 |
| 性能 | 最差 | 良好 | 最高 |
| 部署要求 | 无特殊要求 | 内核支持 VXLAN | 节点 L2 互通 |
| 适用场景 | 仅演示原理 | 公有云、虚拟化环境,生产通用 | 同 L2 广播域的自建机房 |
| 控制方式 | flanneld 进程转发 | VTEP 内核隧道 | 路由表 |
VXLAN 是 Flannel 的默认和推荐模式。UDP 模式仅作演示理解原理,Host-GW 在不跨网段的场景下性能最优。