Kubernetes网络模型:从Flannel到Calico的深度剖析与选型之道

本文旨在为中高级工程师与架构师提供一份关于Kubernetes网络模型的深度技术指南。我们将绕开基础概念的冗长介绍,直击问题的核心:在众多CNI(Container Network Interface)实现中,为何Flannel与Calico成为事实上的两种主流范式?本文将从操作系统内核、网络协议栈的底层原理出发,剖析两者在设计哲学、实现机制上的本质差异,并通过量化的Trade-off分析,为你在不同业务场景下(从小型业务集群到大规模、高性能、零信任安全网络环境)做出精准的技术选型提供坚实的决策依据。

现象与问题背景

Kubernetes作为一个容器编排系统,其本身并不直接实现网络通信。它提出了一套标准化的网络模型,并要求任何接入的集群网络方案必须满足以下基本原则:

  • Pod IP的唯一性:集群中每一个Pod都拥有一个全局唯一的IP地址。这意味着Pod A可以直接通过Pod B的IP地址与其通信,无需进行网络地址转换(NAT)。
  • 节点与Pod的互通:集群中的任何节点(Node)都可以直接通过Pod的IP地址访问该Pod,反之亦然,同样无需NAT。
  • Pod内部IP的一致性:Pod内部容器看到的自身IP地址,与外部节点或其他Pod访问它时使用的IP地址是完全相同的。

这些原则看似简单,但在一个跨越多台物理机或虚拟机的分布式环境中实现起来,却充满了挑战。容器运行在独立的网络命名空间(Network Namespace)中,与宿主机网络隔离。当一个Pod需要与另一个位于不同宿主机上的Pod通信时,数据包如何从一个隔离的虚拟环境,穿越宿主机网络,跨越物理网络,最终精确抵达另一个隔离的虚拟环境?这正是所有CNI网络插件需要解决的核心问题。Flannel和Calico为此提供了两种截然不同但极具代表性的解决方案。

关键原理拆解

要理解Flannel和Calico的差异,我们必须回归到底层的Linux内核网络虚拟化技术和网络路由原理。它们是构建所有现代容器网络方案的基石。

  • 网络命名空间 (Network Namespace):这是Linux内核提供的核心隔离机制。每个Namespace都拥有一套独立的网络资源,包括网络接口(interfaces)、路由表(routing tables)、ARP表和iptables规则。容器技术正是利用它来创建独立的网络环境,使得每个Pod仿佛都拥有自己的“网卡”和“IP地址”。
  • 虚拟以太网设备对 (veth pair):这是一对成对出现的虚拟网络接口,可以看作一根虚拟的“网线”。数据从一端(如Pod的eth0)发出,会立即在另一端(如宿主机的vethXXX)出现。它是连接Pod的Network Namespace与宿主机Root Namespace的桥梁。
  • 网桥 (Linux Bridge):工作在数据链路层(L2)的虚拟交换机。在宿主机上,通常会创建一个名为`cni0`或`docker0`的网桥,所有连接到该宿主机的veth pair的一端都会接入这个网桥。这使得同一宿主机上的所有Pod可以通过这个虚拟交换机互相通信。
  • CNI (Container Network Interface):这是由CoreOS(现为Red Hat)提出的一个标准接口规范。它极大地解耦了容器运行时(如containerd)与网络实现。当Kubelet需要创建或销毁Pod时,它会调用符合CNI规范的二进制插件(如`flannel`、`calico`),并传入`ADD`或`DEL`等命令,由插件负责完成Pod网络命名空间的配置、veth pair的创建、IP地址的分配(IPAM)以及路由规则的设置。
  • Overlay vs. Underlay 网络模型:这是理解Flannel与Calico分野的关键。
    • Overlay(覆盖网络):它在现有的物理网络(Underlay)之上构建一个独立的虚拟网络层。当Pod A的数据包要发送给不同节点的Pod B时,Overlay网络方案会先将这个原始数据包进行“再封装”,套上一个外层的IP头和UDP/VXLAN头。外层IP头的源和目的是Pod A和Pod B所在的宿主机IP。数据包在物理网络中实际上是按宿主机IP进行路由的。当目标宿主机收到后,再“解封装”,取出原始数据包,投递给Pod B。Flannel的VXLAN模式是典型的Overlay网络。
    • Underlay(底层网络):它不创建新的虚拟网络层,而是直接利用底层物理网络的路由能力。它会设法让物理网络(路由器、交换机)直接识别并路由Pod的IP地址。这意味着从Pod A发出的数据包,其源IP就是Pod A的IP,目的IP就是Pod B的IP,全程无需封装解封装。Calico的BGP模式是典型的Underlay网络。

系统架构总览

尽管都是通过DaemonSet在每个节点上运行一个Agent,Flannel和Calico的内部组件和工作流程却大相径庭。

Flannel (VXLAN模式) 架构:

Flannel的设计哲学是“简单、可用”。它致力于提供一个能跨越任何三层网络的扁平化Pod网络。其核心组件包括:

  • flanneld (Daemon):运行在每个节点上的守护进程。它的主要职责是:
    1. 从etcd(Kubernetes的etcd或独立的etcd)中获取整个集群的Pod网络CIDR配置。
    2. 为自己所在的节点申请一个唯一的子网(Subnet),并将节点的IP与分配到的子网的映射关系写回etcd。
    3. 监听etcd中其他节点子网的变化,据此维护一个路由信息表。
    4. 创建并管理一个名为`flannel.1`的VXLAN隧道设备(VTEP – VXLAN Tunnel Endpoint)。
  • etcd:作为Flannel的中央存储,存放网络配置、各节点的子网分配信息以及节点公网IP等。Kubernetes集群本身的etcd通常被复用于此。
  • CNI Plugin:一个名为`flannel`的二进制文件,在Pod创建时被Kubelet调用,负责配置veth pair和`cni0`网桥。

文字描述的架构图景是:一个中心化的etcd存储着全网的“IP地址分配地图”,每个节点上的flanneld都是一个“地图阅读者”和“本地交通管理员”,它根据地图信息,通过`flannel.1`这个“时空隧道入口”(VTEP),将跨节点的数据包封装后送入物理网络。

Calico (BGP模式) 架构:

Calico的设计哲学是“高性能、强策略、可扩展”。它将每个Kubernetes节点都变成一个虚拟路由器(vRouter),通过标准的BGP协议来宣告和学习Pod IP的路由,从而实现网络互通。核心组件包括:

  • calico-node (Daemon):同样以DaemonSet形式运行在每个节点,但它是一个容器集,内部包含两个关键进程:
    • Felix:Calico的核心代理。它负责在内核中编程路由规则、ACLs(访问控制列表)、以及实现Network Policy所需的一切。Felix会监听etcd或Kubernetes API Server来获取Pod、NetworkPolicy等资源的变化,然后将这些高级规则翻译成内核能够理解的iptables规则或eBPF程序。
    • BIRD:一个开源的、功能完备的BGP客户端。它负责从Felix获取本节点上Pod的CIDR路由信息,并通过BGP协议将这些路由“广播”给集群中的其他节点。同时,它也接收来自其他节点的路由信息,并将其写入本节点的内核路由表。

  • etcd / Kubernetes API Server:作为Calico的数据存储,存放网络策略、IP池配置、节点状态等。现代Calico版本推荐直接使用Kubernetes API作为数据存储,以简化部署。
  • CNI Plugin:名为`calico`的二进制文件,负责Pod创建时的基础网络设置,如创建veth pair、将其一端放入Pod的namespace,并调用Calico的IPAM模块分配IP。

文字描述的架构图景是:整个集群构成了一个去中心化的BGP网络。每个节点上的BIRD进程都是一个“路由器”,它们互相交换“寻路信息”(Pod路由)。当数据包产生时,内核直接像查询互联网路由一样,根据路由表找到下一跳地址,高效地将数据包发往目标节点。

核心模块设计与实现

现在,我们切换到极客工程师的视角,深入代码和命令行,看看数据包究竟是如何流动的。

Flannel (VXLAN模式) 的数据包之旅

假设Pod A (10.244.1.10) 在Node 1 (192.168.0.101) 上,要访问Pod B (10.244.2.20) 在Node 2 (192.168.0.102) 上。Node 1上由flanneld分配的子网是`10.244.1.0/24`,Node 2是`10.244.2.0/24`。

  1. Pod A发出数据包:一个源IP为`10.244.1.10`,目的IP为`10.244.2.20`的IP包从Pod A的`eth0`发出。
  2. 到达cni0网桥:数据包通过veth pair到达宿主机Node 1的`cni0`网桥。
  3. 内核路由决策:`cni0`网桥像一个交换机,但数据包的目的IP不在本地链路,需要路由。内核查询Node 1的路由表。flanneld早已创建了这样一条关键路由:

# 在 Node 1 上执行 ip route show
$ ip route show
...
10.244.0.0/16 dev cni0 proto kernel scope link src 10.244.1.1
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
...

这条路由规则`10.244.2.0/24 via 10.244.2.0 dev flannel.1`告诉内核:要去往`10.244.2.0/24`网段,请把包交给`flannel.1`设备处理。`via 10.244.2.0`在这里有些误导性,关键是`dev flannel.1`。

  1. VXLAN封装:`flannel.1`是一个VTEP设备。当它收到数据包后,内核的VXLAN驱动会介入。它会查询自己的转发表(FDB),找到`10.244.2.0/24`这个子网对应的VTEP(也就是Node 2的IP)。这个信息是flanneld从etcd获取后配置给内核的。

# 在 Node 1 上查看flannel.1的FDB表
$ bridge fdb show dev flannel.1
00:00:00:00:00:00 dst 192.168.0.102 self permanent

内核将原始IP包(`10.244.1.10` -> `10.244.2.20`)作为Payload,外面依次封装上VXLAN头(包含一个VNI,用于网络隔离),UDP头(通常是8472端口),以及最外层的IP头。外层IP头的源是Node 1的IP `192.168.0.101`,目的IP是Node 2的IP `192.168.0.102`。

  1. 物理网络传输:这个被封装后的UDP包在物理网络中被正常路由到Node 2。
  2. 解封装与投递:Node 2的网卡收到这个UDP包。内核识别出8472端口是VXLAN流量,交给`flannel.1`设备处理。VXLAN驱动解开封装,还原出原始IP包,然后将其推送到`cni0`网桥,最终通过veth pair送达Pod B。一次跨节点通信完成。

Calico (BGP模式) 的数据包之旅

同样,Pod A (10.244.1.10) 在Node 1 (192.168.0.101) 上,访问Pod B (10.244.2.20) 在Node 2 (192.168.0.102) 上。Calico为每个Pod分配IP,假设分配的CIDR与Flannel相同。

  1. Pod A发出数据包:一个源IP为`10.244.1.10`,目的IP为`10.244.2.20`的IP包从Pod A的`eth0`发出。
  2. 到达宿主机内核:数据包通过veth pair(Calico通常会为每个veth设备开启`proxy_arp`并设置路由)直接到达宿主机的网络协议栈。
  3. 内核路由决策:内核查询Node 1的路由表。由于所有节点上的BIRD进程已经通过BGP交换了路由,Node 1的路由表是这个样子的:

# 在 Node 1 上执行 ip route show
$ ip route show
...
10.244.1.10 dev caliXXXXXXXXX scope link  # 到本节点Pod的直连路由
10.244.2.0/24 via 192.168.0.102 dev eth0 proto bird # BIRD协议注入的路由
...

这条路由`10.244.2.0/24 via 192.168.0.102 dev eth0`是整个流程的关键。它清晰地告诉内核:要去往`10.244.2.0/24`网段(Pod B所在网段),下一跳(next-hop)就是Node 2的IP `192.168.0.102`,并且从`eth0`网卡发出去。注意,这里没有`flannel.1`这样的隧道设备。

  1. 直接转发:内核直接将原始IP包(`10.244.1.10` -> `10.244.2.20`)从`eth0`发出。这个包没有被任何形式地封装。
  2. 物理网络传输:物理网络(交换机/路由器)只需要能够将这个包路由到Node 2即可。在一个二层直连的网络中,Node 1会通过ARP找到Node 2的MAC地址,然后将封装了IP包的以太网帧发过去。在一个三层网络中,需要物理路由器也参与BGP或者有静态路由。
  3. 目标节点接收:Node 2的`eth0`收到这个IP包。由于目的IP `10.244.2.20`是本节点上的一个Pod,Node 2的内核根据自己的路由表(`10.244.2.20 dev caliYYYYYYYYY scope link`),直接将包转发给对应的veth接口,送达Pod B。

一个关键实现细节:Calico的网络策略

Calico的强大之处在于其网络策略。当你在Kubernetes中定义一个`NetworkPolicy`资源时,Calico的Felix进程会将其翻译为`iptables`规则。它会为每个Pod的veth接口创建特定的iptables链(chains),例如`cali-fw-caliXXXXXXXXX`和`cali-tw-caliXXXXXXXXX`。所有进出该veth接口的流量都必须先经过这些链的过滤。这种基于iptables的实现,虽然在规则数量巨大时有性能损耗,但功能强大且成熟稳定。

性能优化与高可用设计 (Trade-off 分析)

选择Flannel还是Calico,本质上是在不同维度的工程目标之间做权衡。

  • 网络性能 (吞吐量/延迟)
    • Calico (BGP): 胜出。由于没有封包/解包的开销,它的性能几乎等同于裸机网络。数据包路径最短,CPU消耗最低。对于网络敏感型应用,如数据库、消息队列、实时计算,Calico的优势非常明显。
    • Flannel (VXLAN): 劣势。VXLAN封装/解封装会消耗CPU资源。更重要的是,它引入了额外的包头(IP+UDP+VXLAN头大约50字节),这会降低有效载荷(payload)的比例。如果MTU(最大传输单元)配置不当,很容易引发IP包分片,或者出现“MTU黑洞”问题,导致性能急剧下降甚至网络中断。
  • 功能丰富度 (网络策略)
    • Calico: 压倒性胜出。网络策略是Calico的一等公民和核心功能。它完整支持Kubernetes NetworkPolicy API,并提供了更多扩展功能,如全局网络策略、策略排序等,是实现“零信任网络”的利器。
    • Flannel: 缺失。Flannel本身只专注于解决网络连通性问题,不提供任何网络策略功能。若要实现网络策略,必须与其他组件结合,例如著名的`Canal`项目,就是将Flannel的数据平面与Calico的策略引擎结合使用。
  • 部署运维复杂度与网络依赖
    • Flannel: 胜出。Flannel的VXLAN模式对底层网络几乎没有要求,只要节点间三层可达即可。这使得它在公有云环境(VPC网络)、私有云以及各种复杂的网络拓扑中都能“开箱即用”,部署极其简单。
    • Calico (BGP): 更复杂。在简单的二层扁平网络中,Calico可以配置为`node-to-node mesh`模式,节点间自动建立BGP邻居,部署也相对容易。但在需要跨网段的复杂三层网络中,为了获得最佳性能和可扩展性,可能需要配置Calico与物理网络设备(如ToR交换机)建立BGP邻居关系(`peer with ToR`),这就需要网络团队的深度参与和配合,对运维能力提出了更高要求。
  • 可扩展性
    • Calico: 更优。BGP是为整个互联网设计的路由协议,其扩展性久经考验。当集群规模达到数千节点时,可以通过BGP路由反射器(Route Reflector)来优化BGP邻居关系,避免全网状连接(full-mesh)带来的性能瓶颈。
    • Flannel: 有瓶颈。Flannel依赖etcd来同步全网的节点和子网信息。在超大规模集群中,频繁的Pod创建销毁和节点变更会导致对etcd的大量写操作,可能对etcd集群的性能和稳定性造成压力。

架构演进与落地路径

基于以上分析,我们可以为不同阶段和需求的团队规划出一条清晰的演进路径。

阶段一:初创与探索期

推荐方案:Flannel (VXLAN模式)

对于刚刚起步使用Kubernetes的团队,或者用于开发、测试环境以及小规模的生产集群,Flannel是最佳选择。它的核心优势是简单。你不需要理解复杂的BGP路由,也不需要与网络部门扯皮。它可以让你快速搭建起一个可用的集群,将精力聚焦于业务应用的容器化和编排上。

阶段二:成长与规范期

推荐方案:Canal (Flannel + Calico Policy) 或直接迁移到 Calico (IPIP/VXLAN模式)

当业务发展,集群规模扩大,安全合规要求提高,你需要引入网络策略来隔离不同业务、不同环境(开发/生产)的Pod。此时有两种选择:

  • 平滑过渡 (Canal): 如果你希望最小化对现有网络架构的改动,可以选择Canal。它保留了Flannel简单可靠的VXLAN数据平面,同时引入了Calico强大的策略引擎。这是一种低风险的“打补丁”式升级。
  • 一步到位 (Calico Overlay): Calico自身也支持IPIP(一种类似VXLAN的IP-in-IP封装)和VXLAN模式。直接切换到Calico的Overlay模式,既可以立即获得其强大的网络策略能力,又避免了BGP模式对底层网络的依赖。这为未来切换到更高性能的BGP模式铺平了道路。

阶段三:成熟与极致性能/安全期

推荐方案:Calico (BGP模式),并探索 eBPF 数据平面

对于大规模生产集群,特别是承载着对网络性能和安全有极致要求的核心业务(如金融交易、大数据计算、AI训练),Calico的BGP模式是必然选择。此时,团队的技术能力和运维体系也已成熟,能够驾驭BGP的复杂性,并与网络团队协作,实现与物理网络的深度整合,榨干每一分网络性能。

更进一步,未来的演进方向是eBPF(Extended Berkeley Packet Filter)。Calico、Cilium等领先的CNI项目都已经提供了基于eBPF的数据平面。eBPF允许将网络数据处理逻辑直接注入到内核中运行,绕过了iptables等传统内核网络栈的复杂路径,能够提供更低的延迟、更高的吞吐量以及更强的可观察性。对于追求技术卓越的团队而言,探索并落地eBPF数据平面,将是网络架构演进的下一个里程碑。

延伸阅读与相关资源

  • 想系统性规划股票、期货、外汇或数字币等多资产的交易系统建设,可以参考我们的
    交易系统整体解决方案
  • 如果你正在评估撮合引擎、风控系统、清结算、账户体系等模块的落地方式,可以浏览
    产品与服务
    中关于交易系统搭建与定制开发的介绍。
  • 需要针对现有架构做评估、重构或从零规划,可以通过
    联系我们
    和架构顾问沟通细节,获取定制化的技术方案建议。
滚动至顶部