multus-cni 之初探
欢迎关注微信公众号“云原生手记”
cni是什么
在讲multus-cni之前,首先要明白cni是什么,CNI 是 Container Network Interface 的缩写,是一个标准的通用的接口,用于连接容器管理系统和网络插件。k8s自己没有实现容器网络方案,但是提供了容器网络规范,就是cni,用户可以实现自己的cni插件,目前比较流行的cni插件是 Flannel 、Calico和Cilium。那cni是如何构建容器网络的呢?这得从容器的namespace机制说起,容器运行时为容器提供多个namespace,比如ipc namespace, network namespace,UTS namespace, mount namespace和pid namespace。而涉及网络插件的就是network namespace, 网络插件(即cni插件)负责将 network interface(网络接口,可以理解成网卡) 插入该 network namespace ,然后对network namespace 中的 interface 进行 IP和路由的配置。所以,简单来说,网络插件的主要工作就在于为容器提供网络环境,包括为 pod 设置 ip 地址、配置路由以保证pod在集群内网络的通信。
multus-cni介绍
本文的主题是multus-cni,multus-cni也是属于k8s中的一种cni,只是这种cni有点特殊,它支持将多个网络接口附加到 Kubernetes 中的pod,也就是说pod可以拥有多张网卡(拥有多个ip)。通常来讲,pod中只能配置一张网卡(loopback网卡除外),但是使用multus-cni可以做到配置多张网卡(大于等于2张)。这是通过将 Multus 充当“元插件”来实现的,这是一个可以调用多个其他 CNI 插件的 CNI 插件,这里想下,为什么要用多张网卡呢?场景是什么呢?下面是multus-cni官方给出的例子,pod中带了三张网卡:eth0,net0和net1,三张网卡有什么用呢?可以用于划分流量,比如eth0专门用于与k8s 控制面组件通信作为管理流量,而net0和net1专门用于业务流量。这样通过不同的网卡,可以把流量区分开来。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
适用场景
这边具体讲下multus-cni的使用场景,一般可以在需要网络隔离的情况下使用额外网络,包括分离数据平面流量与控制平面流量。隔离网络流量对以下性能和安全性是很有用的:
- 性能:
用户可以在两个不同的平面上发送流量,以管理每个平面上流量的多少。 - 安全性:
用户可以将敏感的流量发送到专为安全考虑而管理的网络平面,也可隔离不能在租户或客户间共享的私密数据。
如何为pod添加额外的网卡
集群中的所有 Pod 仍然使用集群范围的默认网络,以维持整个集群中的连通性。每个 Pod 都有一个 eth0 接口,附加到集群范围的 Pod 网络。您可以使用 kubectl exec -it <pod_name> – ip a 命令来查看 Pod 的接口。
部署multus-cni插件的时候,你可以看到有一个crd也被部署了,这个crd就是network-attachment-definition,后面简称NAD。如果用户添加使用 Multus CNI 的额外网络接口,例如名称为 net1、net2、…、netN的网卡,也就是需要将额外网络接口附加到Pod,用户必须创建配置来定义接口的附加方式(也就是创建对应的NAD对象):
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: macvlan-conf
spec:
config: '{
"cniVersion": "0.3.0",
"type": "macvlan",
"master": "eth0",
"mode": "bridge",
"ipam": {
"type": "host-local",
"subnet": "192.168.1.0/24",
"rangeStart": "192.168.1.200",
"rangeEnd": "192.168.1.216",
"routes": [
{ "dst": "0.0.0.0/0" }
],
"gateway": "192.168.1.1"
}
}'
上面NAD对象中使用到了macvaln和ipam里的host-local是什么?
containernetworking 团队维护的通用 CNI 网络插件(见https://www.cni.dev/plugins/current/),网路插件根据用途分成Main插件、Ipam插件和Meta插件:
- Main插件:主要用来创建具体的网络设备的二进制文件;
- Ipam插件:主要用来负责分配IP地址;
- Meta插件:由CNI社区维护的内部插件。
macvlan就是属于Main插件,host-local属于Ipam插件,在这里我们也可以了解到,cni插件中至少要包含Main插件和Ipam插件。
Main 插件是用于在集群中创建额外的网络:
- bridge:创建基于网桥的额外网络可让同一主机中的 Pod 相互通信,并与主机通信。
- host-device:创建 host-device 额外网络可让 Pod 访问主机系统上的物理以太网网络设备。
- macvlan:创建基于 macvlan 的额外网络可让主机上的 Pod通过使用物理网络接口与其他主机和那些主机上的 Pod 通信。附加到基于 macvlan 的额外网络的每个 Pod 都会获得一个唯一的 MAC 地址。
- ipvlan:创建基于 ipvlan 的额外网络可让主机上的 Pod 与其他主机和那些主机上的 Pod 通信,这类似于基于 macvlan 的额外网络。与基于 macvlan 的额外网络不同,每个 Pod 共享与父级物理网络接口相同的 MAC 地址。
- SR-IOV:创建基于 SR-IOV 的额外网络可让 Pod 附加到主机系统上支持 SR-IOV 的硬件的虚拟功能 (VF) 接口。
Ipam插件主要用来负责分配IP地址:
- dhcp插件,节点上需要有 DHCP server;
- host-local插件是给定子网范围,在单个几点上基于这个子网进行ip地址分配;
- static插件,静态地址管理,直接指定ip地址使用的。
如何部署
执行:
wget https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset-thick-plugin.yml
kubectl apply -f multus-daemonset-thick-plugin.yml
一个官方小例子
multus-cni官方给出了一个macvlan的例子,先创建一个macvlan的NAD对象(NetworkAttachmentDefinition),对象中指明了使用macvlan的方式为pod构建容器网络环境,ipam(ip地址分配)使用的是最普通的host-local,子网cidr为192.168.1.0/24,还设置了rangeStart和 rangeEnd进一步明确分配地址的范围:
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: macvlan-conf
spec:
config: '{
"cniVersion": "0.3.0",
"type": "macvlan",
"master": "eth0",
"mode": "bridge",
"ipam": {
"type": "host-local",
"subnet": "192.168.1.0/24",
"rangeStart": "192.168.1.200",
"rangeEnd": "192.168.1.216",
"routes": [
{ "dst": "0.0.0.0/0" }
],
"gateway": "192.168.1.1"
}
}'
然后创建pod,pod的k8s.v1.cni.cncf.io/networks注解中指明nad对象的名字,
pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: samplepod
annotations:
k8s.v1.cni.cncf.io/networks: macvlan-conf #注意
spec:
containers:
- name: samplepod
command: ["/bin/ash", "-c", "trap : TERM INT; sleep infinity & wait"]
image: alpine
运行:
kubectl apply -f pod.yaml
kubectl exec -it samplepod -- ip a
在pod中看到有三张网卡:
lo: loopback 网卡,默认容器里里面都有;
eth0:k8s默认的网络插件创建的网卡;
net1:使用macvlan配置创建的网卡。
你也可以在pod的注解中看到pod的网络状态信息:
kubectl get po samplepod -o yaml
只看注解部分
Annotations: k8s.v1.cni.cncf.io/networks: macvlan-conf
k8s.v1.cni.cncf.io/network-status:
[{
"name": "cbr0",
"ips": [
"10.244.1.73"
],
"default": true,
"dns": {}
},{
"name": "macvlan-conf",
"interface": "net1",
"ips": [
"192.168.1.205"
],
"mac": "86:1d:96:ff:55:0d",
"dns": {}
}]
其中k8s.v1.cni.cncf.io/network-status注解内容是个数组,第一个元素之是k8s 默认网络插件构建的容器网络环境的信息,第二个元素就是macvlan的信息,里面包含了ip地址、mac地址信息和网卡名称等。