Kubernetes 网络虚拟化:Flannel CNI 底层工作原理与数据包流向深度解密 (Wiki)

在 Kubernetes 架构中,CNI(Container Network Interface)网络插件负责为整个集群的 Pod 构建一个扁平化、互通的 IP 网络。Flannel 作为最经典、最轻量级的 CNI 插件,其核心任务是为每个节点分配一个不重叠的子网,并通过网络隧道或路由技术实现“跨主机容器间直接互通”

本知识库站在企业级网络工程师与平台运维视角,深度剖析 Flannel 的底层工作机制,并以同节点 Pod 通信跨节点 Pod 通信(VXLAN 模式)为例,提供详尽的数据包流向与封包解包流程图。


一、 Flannel 核心架构与网段分配机制

Flannel 的核心设计思想是:“大网划分,小网独占”

1. 全局 CIDR 与节点子网租赁

在部署集群时,我们指定了 --pod-network-cidr=10.244.0.0/16

  • 全局 Pod CIDR10.244.0.0/16(拥有约 65,536 个 IP)。
  • 节点子网(Subnet)flanneld 启动时,会向 Kubernetes API Server(实际写入 etcd)申请租赁一个独立的子网段(通常为 /24,拥有 254 个可用 IP)。
    • k8s-master204 分配子网:10.244.0.0/24
    • k8s-worker205 分配子网:10.244.1.0/24
    • k8s-worker206 分配子网:10.244.2.0/24

2. Flannel 核心后台组件

  • flanneld 进程:运行在每个节点上的守护进程,负责向 K8s 监听节点状态,维护本地路由表、ARP 表和 FDB(转发表)。
  • cni0 网桥:本地虚拟二层交换机。每个节点启动时由 CNI 自动创建。同一个节点上的所有 Pod 都通过虚拟网卡对(veth-pair)连接到 cni0 上,IP 地址通常为当前节点子网的第一个 IP(例如 10.244.2.1)。
  • flannel.1 设备:VXLAN 模式特有的 VTEP(VXLAN Tunnel End Point) 虚拟网卡。负责对跨节点的数据包进行硬件级别的 VXLAN 封包(Encapsulation)和解包(Decapsulation)。这里的 .1 代表 VXLAN 的 VNI(VXLAN Network Identifier)为 1。

二、 同节点不同 Pod 相互通信(纯二层转发)

同一台物理机(如 k8s-worker206)上的 PodA 与 PodB 相互通信时,流量完全在宿主机内部流动,不需要经过 flannel.1 进行封包,也不经过物理网卡

1. 技术核心:veth-pair 与虚拟网桥

每个 Pod 在创建时都会生成一对虚拟网卡(veth-pair):

  • 一端留在 Pod 网络命名空间内,命名为 eth0
  • 另一端延伸到宿主机的 Root 网络命名空间,绑定在 cni0 网桥上,命名为 vethxxxx

2. 数据包出入流程图(同节点)

+---------------------------------------------------------------------------------+
|                                 k8s-worker206                                   |
|                                                                                 |
|   +-----------------------+                           +-----------------------+ |
|   |         Pod A         |                           |         Pod B         | |
|   |     10.244.2.2        |                           |     10.244.2.3        | |
|   +---------+-------------+                           +---------+-------------+ |
|             | (eth0)                                            | (eth0)        | |
|             |                                                   |               | |
|     veth-pair                                           veth-pair               | |
|             |                                                   |               | |
|             | (vethA)                                           | (vethB)       | |
|   +---------+---------------------------------------------------+---------+     | |
|   |                                cni0 Bridge                            |     | |
|   |                               (10.244.2.1)                            |     | |
|   +-----------------------------------------------------------------------+     | |
|                                                                                 |
+---------------------------------------------------------------------------------+

3. 数据流向步骤说明:

  1. PodA 发送请求:PodA (10.244.2.2) 试图通过 TCP 访问 PodB (10.244.2.3)。由于目标 IP 在同一个子网内(10.244.2.0/24),PodA 发起 ARP 广播询问 10.244.2.3 的 MAC 地址。
  2. 网桥二层交换:ARP 请求通过 eth0 传出,直接到达宿主机端的 vethA。由于 vethA 桥接在 cni0 上,cni0 网桥(二层交换机)在本地广播该 ARP。
  3. PodB 响应:PodB 收到 ARP 广播,回应其 MAC 地址。
  4. 单播数据传输:PodA 得到 MAC 地址后,将数据包(源 IP 10.244.2.2,目的 IP 10.244.2.3)发送出去,cni0 网桥根据内部的 MAC 地址表,直接将数据包单播转发到 vethB,进入 PodB 的 eth0

三、 不同节点不同 Pod 相互通信(VXLAN 模式)

当跨节点通信时(例如运行在 k8s-worker205 上的 PodA 想要访问运行在 k8s-worker206 上的 PodC),流量需要跨越物理三层网络,这就需要使用 Overlay 叠加网络(VXLAN) 技术。

VXLAN 的核心原理是:“MAC in UDP”。即将 Pod 发出的原始二层以太网帧,封装在宿主机的物理 UDP 数据包中,通过物理网络传输到对端宿主机后拆封。

1. 跨节点网络拓扑与接口信息对照表

  • 源端 PodA:IP = 10.244.1.10(在 worker205 上)
  • 宿主机 205 (Node1):物理 IP = 192.168.108.205flannel.1 MAC = MAC_VTEP_1
  • 宿主机 206 (Node2):物理 IP = 192.168.108.206flannel.1 MAC = MAC_VTEP_2
  • 终端 PodC:IP = 10.244.2.20(在 worker206 上)

2. 跨节点 VXLAN 数据包出入流程图(详细版)

  [ Pod A (10.244.1.10) ]
            |
            | (veth-pair)
            v
     [ cni0 (10.244.1.1) ]
            |
      (路由转发到 flannel.1)
            v
  [ flannel.1 (VTEP 封包) ]  <-- 1. 封装内部以太网帧
            |                <-- 2. 封装外部 UDP/IP 头部 (Dst: 192.168.108.206)
            v
   [ 物理网卡 ens33 ]  =========> [ 物理网络传输 ] =========> [ 物理网卡 ens33 ]
   (192.168.108.205)             (UDP Port: 4789)             (192.168.108.206)
                                                                     |
                                                                     v
                                                          [ flannel.1 (VTEP 解包) ]
                                                                     |
                                                               (去外壳,还原 IP 包)
                                                                     v
                                                            [ cni0 (10.244.2.1) ]
                                                                     |
                                                                     v
                                                          [ Pod C (10.244.2.20) ]

3. 数据包流向与封包/解包全步骤详析

第一步:PodA 发送与本地路由(在 Node1 宿主机内)

  1. PodA (10.244.1.10) 想要访问 PodC (10.244.2.20)。
  2. PodA 发现目标 IP 10.244.2.20 不在自己的本地子网(10.244.1.0/24)内,因此将数据包发送给默认网关(即 cni0 网桥,IP 为 10.244.1.1)。
  3. 数据包到达宿主机 Node1 的内核协议栈。内核查看系统路由表:
    # 在 Node1 上查看路由
    ip route
    # 输出中包含类似这一行:
    10.244.2.0/24 dev flannel.1 proto kernel scope link src 10.244.1.0
    
    内核决策:去往 10.244.2.0/24 网段的数据包,应该发送给本地虚拟设备 flannel.1

第二步:flannel.1 (VTEP) 的二层封装(Overlay 开始)

  1. 数据包到达 flannel.1 设备。因为 flannel.1 是一个二层设备,它需要将 IP 包封装成二层以太网帧。
  2. 寻找目的 VTEP MAC 地址
    flannel.1 需要知道对端宿主机(Node2)上 flannel.1 设备的 MAC 地址。宿主机上的 flanneld 进程早已通过 K8s API 获取了该信息,并强行写入了本机的 ARP 缓存表中:
    # 在 Node1 上查看静态 ARP
    arp -an | grep flannel
    # 会有对端 VTEP MAC 的静态记录
    
    flannel.1 填入内层 MAC 头部
    • 内层源 MACMAC_VTEP_1(Node1 的 flannel.1 硬件地址)
    • 内层目的 MACMAC_VTEP_2(Node2 的 flannel.1 硬件地址)

第三步:内核进行物理 UDP 封装(VXLAN 外壳)

  1. 内层帧封装完毕后,Linux 内核的 VXLAN 驱动将其装入一个标准的 UDP 数据包。
  2. 封装外层 UDP 头部
    • 目的端口:标准的 VXLAN 端口 4789(IANA 规定端口)。
  3. 封装外层 IP 头部(确定物理路由路径):
    为了知道目的 VTEP MAC 对应的物理机 IP 到底是谁,内核需要查询 FDB(转发表)
    # 查看 VTEP MAC 对应的物理机目标 IP
    bridge fdb show dev flannel.1
    # 记录显示:MAC_VTEP_2 指向宿主机 192.168.108.206
    
    由此,内核填入外层 IP 头部
    • 外层源 IP192.168.108.205(Node1 物理网卡 IP)
    • 外层目的 IP192.168.108.206(Node2 物理网卡 IP)
  4. 封装外层 MAC 头部
    根据物理主机的路由表,填入物理网卡的 MAC 地址。

第四步:跨物理网络传输

  1. 这个伪装成普通 UDP 包的数据,通过 Node1 的物理网卡 ens33 发送出去。在物理网络设备(交换机、路由器)看来,这只是一个普通的、在 192.168.108.205:xxxx192.168.108.206:4789 之间传输的 UDP 包。

第五步:Node2 接收与解包(VTEP 解封)

  1. 数据包到达 Node2 的物理网卡 ens33
  2. 内核协议栈发现这是一个目的端口为 4789 的 UDP 包,自动将其递交给内核中的 VXLAN 驱动程序。
  3. VXLAN 驱动程序(对应的设备是 Node2 上的 flannel.1)剥离外层 MAC、外层 IP、UDP 头部以及 VXLAN 报头,露出内层的原始以太网帧(源 IP 10.244.1.10,目的 IP 10.244.2.20)。

第六步:本地网桥转发(数据面收尾)

  1. Node2 的内核协议栈查看本地路由表:
    10.244.2.0/24 dev cni0 proto kernel scope link src 10.244.2.1
    
    决策:该包属于本地 Pod 网段,直接转发给虚拟网桥 cni0
  2. cni0 网桥在本地进行标准的二层交换,通过 veth-pair 设备将原始 IP 包送入 PodC 内部。PodC 成功接收到请求。

四、 跨主机数据包结构对比图

为了能生动地在 Wiki 博客中展示,我们来看一个数据包在物理网卡上传输时的“套娃”结构变化:

封装层次 字段名称 填充数据 (对应本案) 说明
外层 外层目的 MAC Node2 物理网卡 MAC 决定下一跳的物理流向
外层 外层源 MAC Node1 物理网卡 MAC 物理设备寻址
外层 外层目的 IP 192.168.108.206 Node2 物理宿主机 IP
外层 外层源 IP 192.168.108.205 Node1 物理宿主机 IP
外层 外层 UDP 端口 4789 标准 VXLAN 监听端口
中层 VXLAN 报头 VNI = 1 网络隔离标识
内层 内层目的 MAC MAC_VTEP_2 (Node2 flannel.1) 虚拟网络二层目标
内层 内层源 MAC MAC_VTEP_1 (Node1 flannel.1) 虚拟网络二层源
内层 内层目的 IP 10.244.2.20 终端应用 PodC IP
内层 内层源 IP 10.244.1.10 源端应用 PodA IP
内层 Payload HTTP / TCP 真实业务数据 原始报文体

五、 企业级延伸:VXLAN 模式与 Host-GW 模式对比

1. Host-GW (Host Gateway) 模式

  • 工作机制:纯三层路由模式。不进行任何 VXLAN 封包,而是将每个主机的物理网卡直接作为去往对应 Pod 网段的下一跳网关
  • 路由表形态:在 Node1 上会多出一条静态路由:10.244.2.0/24 via 192.168.108.206 dev ens33
  • 优缺点
    • 优点性能极高。没有封装与拆封的 CPU 损耗,吞吐量和延迟接近物理网络。
    • 缺点限制严重。所有物理节点必须处于同一个二层网络(即同一个 VLAN 下,不能跨路由器/三层交换机)。

2. VXLAN 模式

  • 工作机制:Overlay 叠加网络模式。
  • 优缺点
    • 优点极其灵活。支持跨三层物理网络寻址,只要宿主机之间 IP 可达,无论它们处于哪个机房或子网,都可以构建扁平化的容器网络。
    • 缺点存在性能损耗。由于每个包都要多封一层 UDP 外壳,在大流量、高吞吐场景下,会有一定的 CPU 资源消耗。

3. 企业选型建议

  • 如果是自建物理机集群、或在同一个交换机下的虚拟化环境,追求极致性能,建议修改 Flannel 配置切换为 Host-GW 模式。
  • 如果是公有云跨子网混合云环境、或者节点网络结构复杂,建议使用默认的 VXLAN 模式以保障最大的兼容性与连通性。
posted on 2026-05-31 09:43  LeeHang  阅读(59)  评论(0)    收藏  举报