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插件的工作流程其实很简单:
- Kubelet创建Pod的Network Namespace
- 调用CNI插件(通过二进制文件或gRPC)
- CNI插件在Namespace中创建网络接口
- 分配IP地址,配置路由规则
- 返回结果给Kubelet
我在项目中遇到过一个问题:默认的CNI插件(比如Flannel、Calico)只能给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)来完成。
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——除非额外配置子接口。
4.4 SR-IOV设备插件:让Pod直接操作硬件
SR-IOV(Single Root I/O Virtualization)是真正的高性能方案。它允许一个物理网卡(PF)虚拟出多个虚拟功能(VF),每个VF都可以直接分配给Pod使用。
为什么SR-IOV适合RoCE?因为VF是硬件级别的虚拟化,数据面完全绕过宿主机内核,直接由网卡硬件处理。延迟可以降到微秒级,吞吐量接近线速。
SR-IOV在K8s中的部署需要两个组件:
- SR-IOV设备插件:负责发现VF资源,并上报给Kubelet
- 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几乎是唯一的选择。当然,代价就是配置更复杂,资源管理更精细。
ip link show查看VF状态,用ethtool -i确认驱动版本。我曾经因为驱动版本不匹配,折腾了两天才发现是VF创建失败。
公众号:蓝海资料掘金营,微信deep3321