4、Kubernetes网络模型:CNI插件原理、Multus多网卡方案、Macvlan/IPvlan配置、SR-IOV设备插件

聊到Kubernetes网络,很多刚接触的朋友会觉得头大。其实说白了,K8s的网络模型就一个核心原则:每个Pod都有一个独立的IP,Pod之间可以直接通信,不用管它们在哪个节点上。这个设计很优雅,但落地的时候,你会发现事情没那么简单——尤其是当我们想把RoCE这种高性能网络塞进去的时候。

我个人习惯把K8s网络分成三层来看:Pod内部网络、节点间网络、以及外部访问网络。今天咱们重点聊的是Pod内部网络怎么打通,以及怎么让Pod用上SR-IOV这种高性能网卡。

4.1 CNI插件原理:K8s网络的“接线员”

CNI,全称Container Network Interface,是K8s用来给Pod分配网络资源的标准接口。你可以把它想象成一个“接线员”——当Kubelet要创建Pod时,就会调用CNI插件来给Pod插上网线。

CNI插件的工作流程其实很简单:

  1. Kubelet创建Pod的Network Namespace
  2. 调用CNI插件(通过二进制文件或gRPC)
  3. CNI插件在Namespace中创建网络接口
  4. 分配IP地址,配置路由规则
  5. 返回结果给Kubelet

我在项目中遇到过一个问题:默认的CNI插件(比如Flannel、Calico)只能给Pod分配一个网卡。但RoCE场景下,我们往往需要管理网络和数据网络分离。这时候,单网卡方案就不够用了。

核心要点:CNI插件决定了Pod的网络能力。默认插件只支持单网卡,而RoCE需要多网卡协同。

4.2 Multus多网卡方案:给Pod插上“双翅膀”

Multus是一个“meta”CNI插件,它本身不创建网络,而是负责协调多个CNI插件。你可以把它理解成一个“网络交换机”——它把多个网络接口(eth0、net1、net2...)都挂到同一个Pod上。

Multus的工作原理:

  • Pod的yaml中通过k8s.v1.cni.cncf.io/networks注解指定多个网络
  • Multus读取注解,依次调用对应的CNI插件
  • 每个CNI插件创建一个网络接口,分配独立的IP
  • Pod内部可以看到多个网卡,分别对应不同的网络

举个例子,一个Pod需要同时接入管理网络(eth0)和RoCE网络(net1):

apiVersion: v1
kind: Pod
metadata:
  name: roce-pod
  annotations:
    k8s.v1.cni.cncf.io/networks: macvlan-roce
spec:
  containers:
  - name: roce-app
    image: ubuntu:20.04
    command: ["sleep", "infinity"]

嗯,这里要注意:Multus本身不处理网络策略,它只是“搭桥”。真正的网络配置,还是由底层的CNI插件(比如Macvlan、IPvlan)来完成。

避坑指南:我曾经在项目中遇到Multus和默认CNI插件冲突的问题。解决办法是:确保Multus作为“主CNI”配置在kubelet的启动参数中,而其他CNI作为“附属插件”由Multus调用。

4.3 Macvlan/IPvlan配置:轻量级网络虚拟化

Macvlan和IPvlan是Linux内核提供的网络虚拟化技术。它们不需要创建bridge或overlay网络,而是直接让Pod“挂”在宿主机的物理网卡上。

Macvlan:每个Pod获得一个独立的MAC地址,看起来就像一台独立的物理机。适合需要直接暴露在物理网络中的场景。

IPvlan:所有Pod共享宿主机的MAC地址,但使用不同的IP地址。更节省MAC地址资源,但兼容性稍差。

配置Macvlan CNI插件很简单:

{
  "cniVersion": "0.3.1",
  "name": "macvlan-roce",
  "type": "macvlan",
  "master": "ens3f0",        # 宿主机的RoCE网卡
  "mode": "bridge",
  "ipam": {
    "type": "host-local",
    "ranges": [
      [{"subnet": "192.168.100.0/24"}]
    ]
  }
}

我个人习惯用Macvlan的bridge模式,因为它允许同一个宿主机上的Pod之间直接通信,不需要经过外部交换机。但要注意:Macvlan模式下,宿主机本身无法直接访问Pod的IP——除非额外配置子接口。

警告:Macvlan和IPvlan都依赖宿主机的物理网卡。如果物理网卡down了,所有Pod的网络都会中断。生产环境建议使用bonding或team技术做网卡冗余。

4.4 SR-IOV设备插件:让Pod直接操作硬件

SR-IOV(Single Root I/O Virtualization)是真正的高性能方案。它允许一个物理网卡(PF)虚拟出多个虚拟功能(VF),每个VF都可以直接分配给Pod使用。

为什么SR-IOV适合RoCE?因为VF是硬件级别的虚拟化,数据面完全绕过宿主机内核,直接由网卡硬件处理。延迟可以降到微秒级,吞吐量接近线速。

SR-IOV在K8s中的部署需要两个组件:

  1. SR-IOV设备插件:负责发现VF资源,并上报给Kubelet
  2. SR-IOV CNI插件:负责将VF挂载到Pod的Network Namespace中

配置示例:

apiVersion: v1
kind: Pod
metadata:
  name: sriov-pod
  annotations:
    k8s.v1.cni.cncf.io/networks: sriov-roce
spec:
  containers:
  - name: roce-app
    image: ubuntu:20.04
    resources:
      requests:
        intel.com/sriov_vf: 1
      limits:
        intel.com/sriov_vf: 1

这里有个关键点:SR-IOV VF的数量是有限的。一个物理网卡通常只能创建几十到几百个VF。所以你需要提前规划好Pod的密度。

我记得有一次,客户要求每个节点运行50个RoCE Pod,但网卡只支持64个VF。最后我们用了两个物理网卡做bonding,每个网卡分出32个VF,才满足了需求。

性能对比:
方案 延迟 吞吐量 CPU开销 适用场景
Macvlan 中等 通用网络
IPvlan 中等 MAC地址受限环境
SR-IOV 极低 极高 极低 RoCE/DPDK高性能场景

最后说一句:选择哪种方案,取决于你的业务需求。如果只是普通网络,Macvlan就够了。但如果要跑RoCE这种高性能网络,SR-IOV几乎是唯一的选择。当然,代价就是配置更复杂,资源管理更精细。

我的经验:在部署SR-IOV之前,一定要先在宿主机上验证VF是否正常工作。用ip link show查看VF状态,用ethtool -i确认驱动版本。我曾经因为驱动版本不匹配,折腾了两天才发现是VF创建失败。

公众号:蓝海资料掘金营,微信deep3321