☰
K8s网络插件选型:Flannel与Calico原理、性能对比与实战
2026/10/21 13:28:52 网站建设 项目流程

在Kubernetes集群里,至少有一半的网络问题最终都落到CNI插件头上,而flannel和calico这两个插件,又占了CNI插件装机量的绝大多数。我做了多年容器平台运维,每当有新人来问"网络插件选哪个",我的回答从来都不是直接给结论,而是先反问:你的集群要不要做NetworkPolicy?节点是不是同一二层网络?规模会不会超过一百个节点?因为flannel和calico的差异,本质上就是对这些问题的不同回答。

这篇文章不适合当官方文档读,它就是我从大量实操里攒下来的经验总结。内容包括两个插件的底层工作原理差异、部署时的关键配置、性能和故障表现对比,以及最终该如何结合自己的环境做选型。无论你是在准备新集群,还是已经在使用其中某个插件但总遇到说不清的"网络怪现象",这篇都值得花几分钟看完。

1. 为什么每个K8s集群都绕不开flannel和calico

1.1 这两个插件到底解决了什么问题

Kubernetes本身没有实现跨节点网络互通的能力。Pod里的容器会被分配一个集群内IP,但这些IP散落在不同节点上,节点与节点之间怎么把这些Pod网段连通,就是CNI插件要解决的核心问题。flannel和calico都是CNI规范的实现,它们把"所有Pod之间能互通""节点和Pod能互通""Pod对外访问能按规则转换"这三件事变成可落地的机制。

很多刚入门的朋友以为网络插件就是让Pod能上网、Service能解析,其实远远不止。K8s对网络有三条硬性要求:第一,Pod与Pod之间直接通信,不需要经过任何形式的NAT;第二,节点上的kubelet可以主动访问Pod;第三,Pod访问集群外部时,源地址转换按正常外发流量处理。这三条只要有一条不满足,集群内部的DNS、监控采集、日志转发就会出各种稀奇古怪的症状,而且这些症状看起来常常跟业务代码毫无关系。

我实际维护中特别关注一个指标:当业务Pod数量增长到几百上千个的时候,路由表的复杂程度和封装产生的CPU开销才是真正考验网络插件的时刻。两台机器的集群里,任何插件都能跑得很好,但规模上来之后,flannel和calico的表现差异会非常明显,这一点后面我会结合实测数据展开讲。

1.2 一个让我彻底改变选型思路的扩容案例

我接手过一套从测试环境直接转上线的集群,用的是flannel的VXLAN模式。刚开始大约一百个节点,跑得还挺平稳。后来业务量上来,节点扩到一百六十个左右的时候,问题开始集中爆发:Pod之间通信间歇性超时,DNS解析动不动就卡几秒,接口偶发抛5xx错误。整个排查持续了将近一周,日志翻了个遍,最后发现根因是VXLAN封装在节点数量上来之后,宿主机层面的ARP表项和内核网络软中断处理出现瓶颈,加上部分老节点的网卡队列配置偏保守,收包能力跟不上数据量。

后来我们把那套集群的网络插件换成calico的BGP模式,同样的业务流量立刻稳定下来。这个案例让我形成了自己的工作习惯:在选型阶段就把"未来三年规模会涨到哪里"作为重要考量,而不是只看当前几十个节点的状态。插件迁移本身是个伤筋动骨的事,能一步到位就别等出故障了再动。

1.3 动工之前必须想清楚的四件事

我建议任何人在部署集群之前,都先把下面四个问题写在纸上:

第一,集群规模预期是多大。十节点以内和两百节点以上,对路由协议和封装机制的要求完全不同。第二,业务方是否明确要求使用Kubernetes NetworkPolicy。如果有多租户隔离、微服务间白名单这类需求,flannel基本可以不考虑了。第三,底层网络能提供什么条件。节点之间是否二层互通?三层设备能不能跑BGP?VLAN的MTU是多少?这些直接决定了两种插件该用哪种模式。第四,节点的操作系统内核版本。Calico的eBPF数据面对内核版本有硬性要求,如果全是旧内核,选了也用不上,还得退回传统数据面。

这四件事不是技术理论,是选型决策的实际边界条件。很多人部署第一天觉得"先随便选一个,后面再调",等到真正要迁移的时候才意识到,网络插件的切换涉及集群内所有节点和所有Pod的重建,代价远高于当初一个正确的选择。

2. 先搞懂底层原理:flannel靠封装,calico靠路由

2.1 Flannel的VXLAN与host-gw模式

flannel的核心设计哲学是"简单可用"。它把跨节点通信的问题通过Overlay网络来解决,最常见的是VXLAN模式。数据流转大概是这样:Pod A的数据包到达本节点的cni0网桥,转给flannel.1虚拟网卡,flannel.1在原始数据包外面包一层VXLAN头,通过UDP端口8472发到对端物理节点。对端的flannel.1收到后解封装,再经由本地的cni0网桥把数据交给目标Pod。

这样一套封装和解封装的动作比较直观,但也带来了两个副作用。第一个是CPU开销,每个包都要做一次额外封装,数据量大的时候节点的软中断占用会明显上升。第二个是MTU变小,VXLAN头占了额外空间,flannel会把Pod网卡的MTU降到1370左右,这样大包在物理链路上不会被分片。如果业务传输大文件或者视频帧,这些开销就会反映到真实吞吐上。

flannel还有一种host-gw模式,直白讲就是不做封装,直接用节点的路由表把Pod网段指到下一跳。性能非常接近物理网络,但前提是所有节点都在同一个二层网络里,且每个节点能直接路由到其他节点的Pod网段。如果跨了VLAN或者云上多个VPC网络,host-gw模式就跑不通,还得退回VXLAN。另外flannel本身不提供NetworkPolicy能力,如果集群要求精细的访问控制,flannel很难满足,需要额外组合其他组件。

flannel的IP分配按节点分片,每个节点拿到一个/24的子网,Pod创建时从本节点的子网里拿IP。因为IP段和节点绑定,Pod在节点内迁移时IP不会乱跳,路由表相对规整。不过这种分配方式也让IP池的扩展不如calico灵活,节点数量上来了,每个节点预分配一整段IP就有点浪费,如果Pod密度不高,地址利用率是偏低的。

2.2 Calico的BGP、Felix和eBPF数据面

calico的核心思路跟flannel完全不同,它选择了一条偏"路由"的路。默认情况下,集群里的每个节点运行两个关键组件:Felix和BIRD。Felix负责维护主机上的路由和iptables规则,BIRD负责运行BGP协议,把本节点上Pod网段的路由信息广播给其他节点。数据包从Pod A出来之后,通过节点的路由表,直接按BGP学习到的路径一跳一跳送到目标Pod所在节点,中间没有额外的封装开销。

在同一二层网络的环境里,calico的BGP是全网状互联,每个节点都跟其他节点建立BGP会话。这种方式在中小规模下非常高效,但节点超过五六十个之后,全互联的连接数会随着节点数平方增长,所以大规模集群里需要额外部署Route Reflector,把BGP会话收敛成星型结构。这个组件在flannel里是没有的,它属于calico体系下负责扩展性的关键角色。

跨二层网络的时候,calico提供IPIP和VXLAN两种隧道模式。IPIP是在原IP包外层再包一个IP头,开销比VXLAN小,但也要注意,很多公有云的网络环境并不允许IPIP协议的流量通过,这时候就得改用VXLAN模式。我在实际部署时遇到不少用户对calico的理解还停留在"纯三层、无封装",结果看到默认配置自动开了IPIP,跨网段流量莫名被丢弃。

calico另一个大杀器是NetworkPolicy,这也是它跟flannel拉开差距的核心功能。Kubernetes自带的NetworkPolicy只能按四层端口和IP做控制,calico则能在此基础上做七层HTTP方法、ICMP类型、基于节点标签的灵活选择等。在微服务多租户场景里,这个能力几乎成了生产级的门槛需求。eBPF数据面则是calico在v3.16之后提供的更激进方案,它把数据转发和控制逻辑下沉到内核eBPF程序里,替代了传统iptables的部分路径,让Service负载均衡和网络策略的执行都更高效,前提是内核版本不低于5.3,且节点需要加载相关eBPF程序,对运维能力有一定要求。

2.3 两个插件的核心组件和数据面差异一览

维度flannelcalico
核心组件flanneld,依赖etcd或Kubernetes APIFelix+BIRD,可选eBPF程序
默认数据面VXLAN封装BGP直连路由转发
跨子网模式VXLANIPIP、VXLAN
封装开销明显BGP模式几乎为零
NetworkPolicy不支持完整支持,并可扩展
大规模扩展有限需要Route Reflector
部署复杂度低较高,组件多

这张表是选型的起点,不是终点。具体情况还要结合集群环境细聊,我后面会给出更细的实测数据。

3. 部署实战:两个插件的安装差异与关键配置

3.1 Flannel部署实操记录

先以一套用kubeadm初始化的集群为例。初始化时候必须用--pod-network-cidr=10.244.0.0/16指定Pod网段,这个值要和flannel配置文件里的Network字段完全一致。然后直接应用flannel的部署清单,kube-fdnn.yml或对应的release文件。应用完成后,会在kube-system命名空间下看到以DaemonSet方式运行的flannel Pod。

部署完成后先别急着跑业务,做三步验证:第一步,kubectl get nodes -o wide查看节点是否Ready;第二步,进入任意一个Pod,ping跨节点的Pod IP,确认跨节点通信正常;第三步,在节点上执行ip route,看有没有自动生成的10.244.x.0/24 via <节点IP>这类路由。如果flannel的Pod一直在CrashLoopBackOff,优先看Pod日志,最常见的原因是configmap里的Network和初始化时的CIDR对不上,或者某个节点的CNI配置文件被其他插件覆盖了。

配置flannel的时候,有几个细节值得单独强调。第一,/etc/cni/net.d/下面不要同时存在多个CNI插件的配置,特别是那些带"conf"后缀的默认文件,否则节点加入集群时CNI调用会错乱。第二,如果底层物理网络MTU不是1500,例如跑在底层Overlay网络或VLAN上时,flannel自动探测出来的MTU可能偏小或偏大,偏大直接表现为TCP大包卡顿但小包正常。我遇到的例子就是底层MTU只有1400,flannel默认按1500推导出内部的1370,结果所有超过1300字节的包全被分片,业务表现为下载文件奇慢,排查了很久才发现要显式设置MTU。第三,旧版本flannel依赖etcd存储网络配置,新版本改用Kubernetes的CRD,如果是从旧版本升级或迁移,要确认存储模式的兼容性。

3.2 Calico部署实操记录

用calico的YAML清单部署时,有几个环境变量会直接决定集群网络行为,必须先改明白。CALICO_IPV4POOL_CIDR一定要和kubeadm初始化时的--pod-network-cidr保持一致,不一致的话calico分配的Pod IP直接不在预期网段,路由表会对不上。

另一个容易踩坑的是网卡探测。服务器往往不止一张网卡,有管理网口、有业务网口、还可能有docker0之类的虚拟网口。calico默认自动探测网卡,但自动探测经常选错。我在新环境部署calico时,几乎一定设置IP_AUTODETECTION_METHOD=interface=eth0,把业务网卡显式指定给calico。这个配置在单网卡机器上无所谓,但多网卡环境里不配的话,路由通告会指向错误的源IP,表现为节点间偶尔通、经常不通,日志里大量BGP session建立失败。

部署完成后,先用kubectl -n calico-system get pods看组件状态,再用calicoctl node status检查BGP peer是否都建立了。如果节点之间地址是三层可达但二层不通,默认的IPIP模式是可以工作的;如果所有节点都在同一二层网络,建议把IPPool的ipipMode设为Never,这样走纯BGP路由,性能更好。Calico的组件比flannel多,资源占用也更高,但如果集群规模养得起这个开销,它的网络策略能力和排障手段会回报你更多。

开启eBPF数据面属于进阶玩法。安装时设置相关环境变量,calico会把kube-proxy的逻辑也纳进来,由eBPF程序处理Service层的负载均衡。这种模式下,每个节点要求内核支持CGROUP和SOCK_OPS等eBPF hook点,而且集群中所有节点都能访问Kubernetes API Server,否则eBPF程序无法获取到Service更新。升级内核或者调整内核参数之前,先在测试集群试一遍,别把生产直接切过去。

3.3 部署前后经常被忽略的配置细节

Flannel和Calico的部署只是个开端,真正决定网络稳定性的,往往是一堆细小的配置选择。

首先看Pod网段规划。Flannel按每节点预分配/24段,Calico则是通过IP池来发地址,IP池大小可以调。如果你的节点数很多但每个节点Pod密度不高,flannel的固定/24分配方式会浪费大量Pod地址。Calico可以通过调整IP池的块大小来适配,比如把blockSize从默认/26调成/27,减少浪费。这个规划在集群建立初期就要考虑,后期改起来牵扯Pod重建,代价非常大。

其次是MTU一致性。Calico的BGP模式直接用物理网卡MTU,IPIP模式下因为多了一层IP头,MTU要减掉20字节,VXLAN模式减掉50字节。很多网络问题表面上表现为"Pod之间通但不快",背地里就是MTU不一致导致的分片重传。建议节点物理网卡、交换机端口、隧道模式的MTU在部署前就拉通检查一遍。

第三点是策略的预配置习惯。用calico却不开NetworkPolicy,相当于买了一套完整的安全工具链但只用了其中路由功能。我建议即使初期没有硬性安全要求,也在测试环境把默认拒绝策略写好,再逐条放行业务端口,养成这种"默认拒绝+白名单"的思路,后面接多租户业务时你就知道优势在哪了。Flannel用户如果实在需要策略能力,可以单独配置其他支持NetworkPolicy的控制器,但这又增加了组件维护成本。

4. 性能与稳定性实测:到底差多少

4.1 同一硬件环境下的带宽与延迟测试

我在自建的测试环境里做过一轮对比,用两台配置完全一致的物理机,16核32G内存,千兆网卡,系统内核5.10。每台机器上跑三个Pod,用iperf3在两台机器上的Pod之间打流量,记录单流吞吐和TCP往返延迟。

测试结果很直观:Calico的BGP直连模式吞吐稳定在930Mbps左右,延迟平均在0.3ms,基本贴近物理网卡本身的能力;Flannel的host-gw模式表现几乎持平,92xMbps;Flannel的VXLAN模式吞吐掉到820Mbps左右,延迟上升到0.5ms——封装和解封装不扣吞吐是不可能的。Calico的eBPF模式在单流场景和BGP直连相差不大,但在高并发小包场景优势明显,CPU占用还更低。

这个结果不意外,但我想强调的是"差异是否可感知"这个角度。如果你的业务主要是HTTP API调用,单请求数据量小,VXLAN带来的那点延迟根本察觉不到;但如果是数据同步、日志传输、AI训练这类带宽敏感型任务,多出的一百多兆吞吐和零点几毫秒延迟,可能就成了瓶颈。选型前最好把业务流量特征一并考虑进去。

4.2 资源消耗与大规模场景下的扩展性

Flannel的组件确实轻量,flanneld进程内存长期在50MB以内,而Calico的Felix在配置较多策略的时候可以吃到200MB以上,BIRD大概几十MB。但别只盯着内存。Flannel的封装路径会让CPU软中断占用明显偏高,在同样的大流量场景里,Flannel节点的CPU使用率往往比Calico节点高五到十个百分点。Calico走纯路由转发,CPU开销集中在路由查找和iptables链上,占用更稳定。

集群规模起来之后,Flannel的路由表和ARP表会先遇到压力。节点几百个时,每次Pod网段变动都要通告全网,旧版本flannel依赖的存储层如果跟不上,路由收敛就会有延迟。Calico的BGP协议天生就是为大规模路由扩散设计的,收敛速度比Flannel的机制快,但全网状BGP会话数会随着节点平方增长,所以需要Route Reflector。我在超过两百节点的集群里一定会提前把Route Reflector规划好,而不是等会话数爆了再补。

4.3 故障现场的两种"崩溃风格"

长期维护的经验告诉我,Flannel出问题的表现是"通不了",Calico出问题的表现则一般是"乱杀或漏杀"。

Flannel故障通常意味着VXLAN隧道没起来、路由表没写对,表现就是某个节点间的Pod互Ping不通,但本节点的Pod访问外部一切正常。这类问题定位起来相对直接,看路由表和flannel日志基本能找到原因。

Calico故障有点不一样,最常见的是策略误判。有一次我在一个测试集群里加了条NetworkPolicy,结果半个命名空间的Pod都失联了,最后发现是因为Policy选择的标签范围写得太宽,把不想限制的Pod也纳入了范围,Felix把规则写入节点iptables后,流量在INPUT链被DROP。这类问题靠iptables -L和calico的日志逐层排查,还需要理解Felix的规则生成顺序,比Flannel的"通不通"问题更考验脑子。

还有一种典型场景:Calico节点换了网卡或IP地址后,IP_AUTODETECTION_METHOD没有显式指定,calico自动探测到了错误的网卡,BGP对端持续老化,数据包出现黑洞——表面上节点都是Ready,Pod也都在Running,但跨节点访问就是不通。这种"看起来正常实则失联"的故障最坑人,所以我反复强调多网卡机器上一定要显式配置网卡探测。

5. 常见故障排查方法与避坑实录

5.1 高频故障速查表

现象涉及插件首要排查命令常见根因
Pod跨节点Ping不通Flannelkubectl logs <flannel-pod>CIDR不一致、MTU错误
Pod跨节点不通Calicocalicoctl node statusBGP会话未建立、网卡选错
节点Ready但Pod访问异常Calicoiptables -L -nNetworkPolicy误拦截
DNS解析经常超时两者CoreDNS日志、节点网络监控网络插件CPU瓶颈、底层丢包
新节点加入后跨节点流量异常Calicoip route get <PodIP>未配置自动发现,路由不通
Service ClusterIP访问不通Calico eBPF检查eBPF程序加载状态内核版本不满足或需要替换代理

表格只是起点,下面的排查思路才是真正能帮你节省时间的东西。

5.2 我惯用的网络故障排查顺序

遇到K8s网络故障,我从来不先重启插件,而是按照一个固定流程走,执行完基本就能锁定问题层级。

第一步,判断故障发生在"Pod到Pod"还是"Pod到Service"。这两个链路用的组件不一样,前者主要依靠CNI路由,后者还叠加了代理规则。第二步,在源节点执行ip route get <目标PodIP>,看路由是否指向正确的下一跳。这一步能很快区分是路由缺失还是封装层故障。第三步,在目标节点看ARP表和iptables规则,确认目标Pod所在机器的MAC和策略链允许放行。第四步,如果还是定位不到,就同时在源、目标节点抓包,一边看包的发送,一边看包的到达,中间哪只收一半,问题就出在哪一段链路。

这套流程对Flannel和Calico都适用。只要你知道当前插件到底是封装型还是路由型,图画出来,故障点基本就浮出水面了。

5.3 三个容易被忽略但频率极高的坑

第一个坑是节点时间不同步。Calico的BGP协议靠KeepAlive维护邻居关系,节点间时间偏差超过一定阈值,KeepAlive会因为序号和时间窗口对不上而断开,日志里全是"BGP peer down",实际是时钟漂移。集群里部署好chrony或ntpd同步,能少很多莫名其妙的网络告警。

第二个坑是DNS配置污染。Pod内解析集群外部域名失败,表面上看起来像网络问题,实际上可能是resolv.conf被改成错误DNS。这种问题经常在排查路由时浪费时间,建议先检查Pod内的DNS配置再动网络层,尤其在使用NodeLocal DNSCache时,配置不彻底会带来一堆偶发超时。

第三个坑是iptables规则数量膨胀。Calico把大量策略实现为iptables规则,当Service或Policy的数量破万后,iptables的查询耗时指数上升,所有流量命中规则链都会变慢。这个阶段要么精简策略数量,要么把数据面切到IPVS或eBPF模式,不然随着业务增长,网络延迟会悄悄恶化。

6. 选型建议:直接告诉你该怎么选

6.1 我的选择标准和决策表

我帮团队踩了这么多坑之后,总结出一套决策标准,按这个标准执行可以少走弯路。

如果集群规模在五十个节点以内,没有多租户策略要求,也没人在意那零点几毫秒的额外延迟,flannel完全够用,而且运维成本极低。如果集群要长期跑生产,规模会持续增长,或者业务已经被要求做网络策略,那就直接上calico。如果底层网络条件允许纯三层路由,且运维团队有人熟悉BGP基础,calico的BGP模式是性能和排查体验最均衡的方案。如果你有追求极致性能的场景,且内核版本足够新,calico的eBPF模式确实能带来可感知的提升。

场景特征推荐插件和模式核心理由
测试环境、几十节点、无策略需求Flannel VXLAN部署简单,资源占用低
生产环境、无策略需求、同二层网络Flannel host-gw性能接近物理网络,运维省心
生产环境、有NetworkPolicy需求Calico BGP/IPIP策略完整,安全边界可控
跨三层网络、集群规模大Calico IPIP或VXLAN路由自动收敛,扩展性优于Flannel
高并发低延迟、内核5.3+Calico eBPF数据面性能最好,CPU占用低

6.2 从Flannel平滑切换到Calico的操作思路

如果你已经在Flannel上跑了生产集群,不想推倒重来,也不是完全没有办法迁移。大思路是先在集群里部署一套Calico,但暂时不改变现有CNI配置,等新节点池使用Calico初始化后,再逐批把节点从Flannel切到Calico。这个过程的难点在于两个插件使用同一个Pod网段,切换时有短暂的IPAM状态不一致,业务Pod会重建,但Service和负载均衡不会中断。

执行前要做的准备工作包括:备份现有网络策略配置,确认应用Pod的副本数可以容忍短暂重建,在非业务时间窗口操作。切换过程中每次只处理一个节点或一小批节点,观察CoreDNS和业务监控指标稳定后再继续。我见过有人图省事一次性把所有节点同时切过去,结果瞬间的网络重建请求把API Server打满,那场面相当狼狈,所以慢就是快。

6.3 我踩了几年坑之后的最终体会

选网络插件这件事,很多时候不是比谁功能多,而是比谁更贴合你的底层网络环境。把Flannel切到Calico,解决不了交换机丢包,也解决不了节点间延迟超标,这些是物理网络层的问题。先把节点网络质量、MTU一致性、时钟同步这些底层地基打好,再谈CNI选型,顺序不能颠倒。

我个人现在的习惯是这样:小规模验证环境一律用Flannel,时间留给业务;面向生产的集群直接用Calico,哪怕初期只用到路由功能,也把策略能力先铺好。网络插件这种底层组件,上线后再换一定是痛苦的,不如最早多花半天时间把需求想透,后面省下的时间是以周计的。希望这篇内容能让你在集群启动之前,就不再为这个"二选一"纠结。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询