上个月接了个运维工单,客户的环境很标准:三台节点的Kubernetes集群,业务Pod分布在不同节点上,平时跑得好好的,某次扩了业务量之后,Pod之间的互访开始变慢。最开始大家都怀疑是节点机器扛不住了,扩容、加内存、加副本数都试过,没用。后来客户把监控摊开一看才发现,真正不对劲的是两个指标:网卡出向带宽长期跑在80%上下,而跨节点调用的p99延迟从原来的18毫秒涨到了40多毫秒。
如果你正在给容器集群挑节点机器,或者想把自建集群迁到更合适的线路上,可以先看看这几家的报价和技术说明:novixlink(服务器与主机),跨节点互联对底层线路的抖动很敏感,网络质量本身就是容器编排体验的一部分。

CNI全称Container Network Interface,也就是容器网络接口。它本身不是一个网络实现,而是一套约定:容器运行时(containerd、CRI-O、docker)要接网络,就按CNI规范调用一组插件,插件负责把容器接进网络,把IP分配出去,把路由和转发规则配好。
这套规范的价值在于解耦。Kubernetes负责调度容器往哪个节点跑,CNI插件负责这些容器怎么互相通。常用的CNI插件有Calico、Flannel、Antrea、Cilium、Weave,各自实现方式不同,但都遵循同一套调用约定。
换句话说,你用kubectl get pod -o wide看到的那个IP,并不是节点上真网卡配出来的地址,而是插件在节点上虚拟出来的地址。节点之间要互相访问这些地址,就得靠插件自己搭一条通道过去。这条通道怎么搭、封装几层、要不要加密,直接决定了跨节点通信的性能上限。

常见的跨节点封装方案大致分三类:
IPIP封装。把原始IP包整个塞进一个新的IP包里,外面再套一层IP头。Calico在某些网络环境下默认走这条路(比如某些云厂商的底层网络不支持BGP传播Pod网段时)。好处是简单、兼容性高,坏处是每包多20字节头,而且内核要额外处理一层封装解封装,CPU开销和延迟都明显。
VXLAN封装。UDP封装,给每个包加一个VXLAN头(8字节)加一个UDP头(8字节),总共16字节。好处是走标准UDP路径,任何支持UDP的底层网络都能跑,性能损耗比IPIP小不少。缺点是对MTU比较敏感,路径上只要有一跳不支持大包,就会触发分片或者ICMP不可达。
BGP直接路由。不封装,插件自己跑BGP,把每个节点的Pod网段直接宣告出去,底层网络按路由转发。这种方式性能最好,但前提是底层网络允许你传BGP会话,很多云环境做不到。
客户那套集群,底层是云厂商的虚拟网络,BGP传不出去,Calico就自动降级到了IPIP模式。节点之间每传一个包都多套一层,小包还好,一旦有批量拉取、大对象传输、或者数据库跨节点同步,链路就被撑起来了。

我一般先算理论上限。假设业务平均MTU是1400字节,IPIP封装后变成1420字节,VXLAN封装后变成1416字节。单看这一层,差别只有4字节,好像可以忽略。但真正的问题不在这里。
关键在于封装后超过底层链路的MTU上限时会发生什么。如果节点MTU还是1500,而底层网络实际只能跑1400,那1420字节的包会被丢,然后触发ICMP报文回来,源主机收到之后把包变小重发。这一个来回,延迟就从几毫秒变成几十毫秒。
客户现场就是这个情况。我们抓包看到大量ICMP destination unreachable-fragmentation-needed,然后是TCP重传。网卡显示带宽跑满,其实是被重传撑起来的,不是真实业务流量大。
解决办法说起来简单:把CNI的MTU配置从1500调到1410(1500减去VXLAN头的16,再减去一点余量),让封装后的包能顺利通过。结果跨节点p99延迟从40多毫秒降到2毫秒左右,带宽利用率也正常了。整整8倍的差距,改的却只是两个配置项。
这里插一句,为什么现在越来越多团队在容器集群这块开始重视底层线路。封装方式你可以调,MTU你可以改,但只要节点之间的物理链路本身抖得厉害、丢包率高,那再好的CNI插件也救不了。跨节点流量对线路质量是放大的,一个5%的基础丢包率,经过封装、队列、调度几层叠加,表现出来的可能是20%的超时。
如果你的集群节点分散在两个机房、或者需要跨云互联,第二家更值得看:backwaves(全球网络与专线互联),提供IEPL、IP Transit和服务器托管,跨机房互联的抖动和丢包是它的主打方向。
从IPIP切到VXLAN不是改一行配置那么简单,我整理了几个我自己踩过的点:
1、MTU必须两端对齐。节点上CNI配置的MTU、底层网络的MTU、以及Overlay接口的MTU,三处要一致。少改一处,症状还是老样子。
2、已有连接不会自动迁移。改完配置后老的长连接还是走老路径,得重建连接才能看到效果。数据库连接池、Kafka消费者这种尤其明显,别以为改完没变化就是没生效。
3、底层网络要支持UDP。有些云厂商的安全组默认会拦掉自定义UDP端口,VXLAN跑不起来,表现出来是节点NotReady或者Pod一直ContainerCreating。
4、加密会再叠一层开销。如果你同时开了IPsec或者Calico的VXLAN加密,封装层数就变成三层,MTU要再往下调,性能还要再打折。加密不是不能开,但要知道自己在开几层。
5、别只看平均延迟。跨节点问题往往体现在p99和丢包上,平均值看着还挺正常。我一般直接看节点网卡的重传统计和ICMP错误计数,这两个指标一有异常,方向基本就定了。

如果不确定自己是不是也踩了这个坑,可以按这个顺序查:
第一步,在两个不同节点上各起一个Pod,用nslookup拿到对方Pod IP,确认能通。
第二步,在节点上看encapsulation配置项是什么模式,不同插件字段名不一样,Calico是ipipMode或者vxlanMode,Flannel看backend类型,Cilium看tunnel协议。
第三步,用iperf3在两个节点之间跑一把,看实际吞吐和重传。命令很简单,iperf3 -c 对端IP -t 30 反向再跑一次iperf3 -c 对端IP -R。
第四步,如果吞吐上不去但延迟也不高,去看MTU。ping -M do -s 1400 对端IP 这种带DF标志的探测最好使,能直接测出实际可用MTU。
我自己排查这类问题的顺序基本是:先看有没有ICMP报错和重传,再看封装模式,最后才调MTU。反过来查基本查不出来,因为封装方式本身不会报错,它只是默默地让一切变慢。
CNI插件这层东西,装的时候几乎没人关注,跑起来之后才发现它决定了跨节点通信的天花板。封装方式选错,MTU没配对,性能问题会以延迟高、重传多、网卡打满的形式出现,而且往往被误判成硬件不够或者网络带宽不够。
如果你正在做集群选型或者排查跨节点性能,可以先跑一遍上面那四步体检,大概率能找到方向。需要在自己的实验环境里对照验证的话,准备几台节点机器加一个像样的底层网络环境就够了,不用一开始就上生产规模。