
基于Multus CNI
实现Kubernetes容器多网络
尊龙时凯工程院
涂立海

Multus CNI简单来说是一种符合CNI(Container Network Interface)规范的开源插件,,,,旨在为实现K8s(Kubernetes) 环境下容器多网卡而提出的解决方案。。它作为一种“元插件”,,,,可以与其他 CNI插件搭配使用。。
1.
背景
一个容器启动后,,,,在默认情况下一般都会只存在两个虚拟网络接口(loopback和eth0),,,而loopback的流量始终都会在本容器内或本机循环,,,,真正对业务起到支撑作用的只有eth0,,当然这对大部分业务场景而言已经能够满足。。

但是如果一个应用或服务既需要对外提供API调用服务,,也需要满足自身基于分布式特性产生的数据同步,,,,那么这时候一张网卡的性能显然很难达到生产级别的要求,,,网络流量延时、、、、阻塞便成为此应用的一项瓶颈。。
基于上述痛点和需求,,容器多网络方案不断涌现。。。而根据开源社区活跃度、、、、是否实现CNI规范以及稳定性,,,,我们采用multus-cni作为在K8s环境下的容器多网络方案。。。
2.
Multus CNI
Multus CNI enables attaching multiple network interfaces to pods in Kubernetes.
以上是Multus CNI项目官方对其存在意义的精简描述,,它的存在就是帮助K8s的Pod(可简单理解为一组容器的集合,,,,是K8s可管理的最小“容器”单位)建立多网络接口。。
Multus CNI 本身不提供网络配置功能,,,,它是通过用其他满足CNI规范的插件进行容器的网络配置。。。。
如图1所示,,在此场景下我们可以把Pod抽象为单个容器。。原本容器里应仅存在eth0接口(loopback忽略不计),,是由主插件产生创建并配置的;而当集群环境存在 Multus CNI 插件,,,,并添加额外配置后,,,,将会发现此容器内不再仅有eth0接口,,,,你可以利用这些新增的接口去契合实际业务需求。。

图1 基于Multus CNI的Pod内部网卡结构
前面有提到主插件、、、元插件,,,,这些究竟代表什么??和Multus CNI有什么关系????要解答这些就绕不开这个问题:什么是 CNI ???
3.
CNI规范
CNI (Container Network Interface), a Cloud Native Computing Foundation project, consists of a specification and libraries for writing plugins to configure network interfaces in Linux containers, along with a number of supported plugins. CNI concerns itself only with network connectivity of containers and removing allocated resources when the container is deleted. Because of this focus, CNI has a wide range of support and the specification is simple to implement.
以上引用了官方对其的描述,,,,简短来讲CNI是一组限于容器网络面的规范,,,定义了容器网络资源创建、、、、管理的规则。。
但它并不仅仅是规范,,,它也包含了库和实现,,,,CNI自身实现并提供了内置且通用的网络插件,,,,同时为第三方实现其规范预留了扩展。。。
CNI 将插件分成三种类型:

到这里,,我们已经明白,,,,Multus CNI 属于Meta类, 它可以与其他第三方插件适配(也就是主插件),,主插件来作为Pod的主网络并且被K8s所感知,,,,它们可以搭配使用且不冲突。。。
4.
场景规划
假设我们已经部署好一个K8s高可用集群,,,使用的主CNI插件是 Calico(其实现已包含Main类型和IPAM类型),,元CNI插件是 Multus CNI,,,但其实Multus本身并没有实现Main类型和IPAM 类型的功能,,,它本质是个插件的调用器,,,,所以还需要另外的Main类型和IPAM类型的插件,,这里我们选用ipvlan和whereabouts (支持跨集群动态分配IP地址) 分别作为multus-cni的Main和 IPAM。。。
同时为解决背景描述的痛点和更贴近生产环境,,,,下面展示时间案例:实现基于Rook部署Ceph(分布式存储系统)时实现Ceph 控制面和数据面的网络流量分离。。。真实生产环境下,,租户将会在集群内产生相当大数量级的持久性存储数据,,,,而对于分布式存储必定要满足高可用特性(即数据和服务存在多副本),,同步庞大数量级的存储数据将导致网络性能的下降,,,如果控制面网络和数据面网络使用同一张网卡分发,,,也会导致用户端明显感知到系统的不稳定性。。因此网络分离有益于提高性能以及提升用户体验。。。。
如图2所示,,Public Network即是控制面网络,,,,Cluster Network即是数据面网络;我们忽略Ceph 这些组件的作用和意义,,,,只从网络流量的流向分析,,,,可以很清晰看出控制面网络用于Ceph组件内部和与外部客户端进行交互;而数据面网络主要用于副本间的数据同步。。。这就要求同时运行控制网络和数据网络组件所在的节点需要有两张可用的网络接口。。。。

图2 Ceph组件网络流向图
前面有提到主插件、、、元插件,,这些究竟代表什么???和Multus CNI有什么关系????要解答这些就绕不开这个问题:什么是 CNI ??
5.
落地实践
有了以上前置知识准备,,,接下来便可以进行实际的验证。。。。
集群规划六个节点(仅做测试环境,,生产环境需重新规划),,三个控制面节点,,,一个LB节点,,,一个计算节点,,,一个存储节点;存储节点部署Ceph。。

5.1. 部署Multus CNI
获取Multus CNI资源清单文件,,准备镜像:

因为Multus CNI使用的是 DaemonSet 类型,,,,所以默认在所有节点都有一个实例,,,以下Whereabouts 同理。。
经观察,,,Pod运行不久后,,,,将会在各节点上的/opt/cni/bin/下生成multus的可执行文件,,,,/etc/cni/下生成网络定义文件以及用于配置集群访问的文件。。。。

可执行文件的作用是配置Pod的网络栈,,,DaemonSet的作用是实现网络互通。。。
注:
一个Network Namespace的网络栈包括:网卡(Network interface)、、、、回环设备(Loopback Device)、、、路由表(Routing Table)和iptables规则。。。
打开 00-multus.conf,,,查看其内容:

其中Multus CNI在K8s环境下的调用关系如图3所示,,在Kubernetes中,,,处理容器网络相关的逻辑并不会在kubelet主干代码里执行,,而是会在具体的CRI(Container Runtime Interface,,,,容器运行时接口)实现里完成。。。。CRI将网络定义文件以JSON格式通过STDIN方式传递给Multus CNI插件可执行文件。。。文件中delegates的意义在于Multus会调用其delegates 指定的插件来执行,,,这里还有一点需要说明下,,,,如果/etc/cni/net.d/ 目录下有多个网络定义文件,,,,CRI只会加载按字典顺序排在第一位的文件(即插件),,即默认情况下创建Pod时使用的是Calico 插件配置网络。。。。

图3 Multus调用链
5.2. 部署Whereabouts
获取Whereabouts 资源清单文件,,,,准备镜像:


经观察,,Pod运行不久后,,将会在各节点上的/opt/cni/bin/ 下生成Whereabouts 的可执行文件,,,/etc/cni/whereabouts.d/下生成网络定义文件以及用于配置集群访问的文件。。。。

5.3. 添加 NAD
NAD即NetworkAttachmentDefinition,,Multus CNI遵循Kubernetes Network Custom Resource Definition De-facto Standard ,,,其提供了一种标准化的方法,,,,通过它来指定附加网络接口的配置。。。。



这里指定了两个NAD,,,,分别对应控制网络和数据网络。。
• 实际使用的Main类型插件为ipvlan,,,,且默认是L2模式。。。。
• IPAM的功能交给了Whereabouts去做。。
• 规定了网络号和可以使用的IP范围(目前使用了同一网段地址,,实际生产应做区分)。。
• 控制网络没有指定网卡,,,,即使用宿主机默认路由所在网卡。。。而数据网络一般使用专用网卡,,,,如果需要在多个节点上部署,,需保证数据网络使用的网卡名相同。。。。
ipvlan是Linux内核提供的特性,,它可以虚拟化宿主接口,,,ipvlan设备(从设备)共享与宿主接口(主设备)相同的MAC 地址。。。。内核驱动程序通过检查每个报文的IP地址来决定由哪个虚拟接口来处理该报文。。在此L2 模式下,,,,TX处理发生在附加到从设备上的堆栈实例上,,然后将数据包切换并排队到主设备以发送。。。。在这种模式下,,,从设备将RX/TX组播和广播。。
5.4. 基于Rook部署Ceph
Rook是采用Operator 模式来部署Ceph的软件,,,它负责管理、、、维护Ceph的生命周期。。。
接下来从官方地址下载所需的资源清单文件,,,,修改 cluster.yaml,,,,添加Multus CNI多网络支持。。。

部署Rook Operator和Ceph:

查看部署结果:

集群规划六个节点(仅做测试环境,,,,生产环境需重新规划),,,三个控制面节点,,一个LB节点,,,,一个计算节点,,一个存储节点;存储节点部署Ceph。。。
5.5. 结果验证
5.5.1 多网络接口是否已创建
根据图2上的展示,,,只有OSD组件是同时使用了控制网络和数据网络,,,,可查看OSD Pod信息进行验证:

现在网卡已正确创建,,,IP 地址也按预期划分范围分配。。。其中10.244.119.46这个地址是由Calico创建和分配的。。
查看存储节点IP地址信息:

可以看出使用IPVlan的控制网络和数据网络的MAC地址和其所在的宿主网卡一致。。
同时再确认其他组件是否已创建出多网络,,如MON组件:

5.5.2 Ceph组件间是否能正常通信
• 进入OSD容器网络命名空间
查看网络设备:

用OSD组件控制面网络所在网卡向MON组件控制网络发送ICMP报文:

• 进入MON组件网络命名空间
查看网络设备:

用MON组件控制面网络所在网卡向OSD组件控制网络发送ICMP报文:

同时用MON组件控制面网络所在网卡向OSD组件数据网络发送ICMP报文:

6.
总结
本文选取Multus CNI插件从理论到实践的角度讲述了如何利用Multus CNI在生产环境下实现容器的多网络,,以及验证了方案的可行性。。。
在生产级别环境下,,,,为了保证稳定性和安全性,,网络根据不同的使用目的进行隔离将是一个必要的措施,,,,比如管理网络、、、控制网络和数据网络的隔离。。。这种程度的隔离在物理机和虚拟机里面很容易实现,,,但是在容器网络里面,,,,例如Kubernetes这样的容器编排平台,,则会面临一些限制,,尤其是现在Kubernetes的Pod默认还不支持多网络设置,,但是业界对容器多网络的需求还是很强烈的。。。。
7.
参考资料
Multus-CNI
Container Network Interface (CNI) Specification
CNI Plugins Overview
The Kubernetes network model
Kubernetes CNI
whereabouts
IPVLAN Driver HOWTO
Rook Cluster CRD
Ceph NETWORK CONFIGURATION REFERENCE

