Bootstrap

multus-cni之初探

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地址信息和网卡名称等。

;