Multus CNI

  • By default, Kubernetes supports a single network interface! For some scenario, we need to implement two or three interfaces in the PODs, so that we can connect to different backend services.
  • Multus is an open-source CNI (Container Network Interface) plug-in for Kubernetes that lets you attach multiple network interfaces to a single pod and associate each with a different address range with the help of CRD objects in Kubernetes. Thus, Multus Containers manages the multiple container network interfaces in Kubernetes.
  • Moreover, it allows to attach DPDK/SRIOV interfaces to pods to support network intensive workloads.
  • Multus is dependent on other types of network plugins, such as Flannel, Calico, Cilium and Weave.

 

  • Role of Multus CNI:
    • In enabling multi-interface support by serving as a supplementary layer in a container network.
    • It attaches multiple network interfaces to pods in Kubernetes.
    • Multus CNI work as an intermediate between container runtime and plugins.

We we know that POD has only single interface eth0 connects Kubernetes cluster network to connect with Kubernetes server/services (e.g. kubernetes api-server, kubelet and so on).

net0 is additional network attachments and connect to other networks 1 by using other CNI plugins (e.g. vlan/vxlan/ptp).

net1 is another additional network attachments and connect to other networks 2 by using other CNI plugins

 

Before the installation of Multus, one can check that there is no network-attachment-definitions resource information is available to Kubernetes cluster.

[root@master1 ~]# kubectl get network-attachment-definitions.k8s.cni.cncf.io 
error: the server doesn't have a resource type "network-attachment-definitions"

We, can install the Multus quickly, by using below command.

[root@master1 ~]# kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset-thick.yml

customresourcedefinition.apiextensions.k8s.io/network-attachment-definitions.k8s.cni.cncf.io created
clusterrole.rbac.authorization.k8s.io/multus created
clusterrolebinding.rbac.authorization.k8s.io/multus created
serviceaccount/multus created
configmap/multus-daemon-config created
daemonset.apps/kube-multus-ds created

[root@master1 net.d]# kubectl get pods -A| grep -i multus
kube-system   kube-multus-ds-28dg4                          1/1     Running   0                2m43s
kube-system   kube-multus-ds-hbddb                          1/1     Running   0                2m43s
kube-system   kube-multus-ds-tnvgf                          1/1     Running   0                2m43s
[root@master1 net.d]# kubectl get network-attachment-definitions.k8s.cni.cncf.io 
No resources found in default namespace.

From the above output, it is clear that our Kubernetes cluster knows about the network-attachment-definitions object.
[root@master1 net.d]#  cd /etc/cni/net.d/
[root@master1 net.d]# cat 00-multus.conf | jq .
{
  "capabilities": {
    "bandwidth": true,
    "portMappings": true
  },
"cniVersion": "0.3.1", #Tells each CNI plugin which version is being used
  "logLevel": "verbose",
  "logToStderr": true,
  "name": "multus-cni-network",
  "clusterNetwork": "/host/etc/cni/net.d/10-calico.conflist",
"type": "multus-shim" # This tells CNI which binary to call on disk.
}
[root@master1 net.d]#

As we know that every VM has different interfaces and gateway. Thus, we need to create one configuration file that contain the correct information. For that, first we need to identify the correct interface and gateway.

 

 

[root@master1 ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:4f:74:7d:a6  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.31  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::a00:27ff:fe22:8301  prefixlen 64  scopeid 0x20<link>
        inet6 2401:4900:1c0a:4e0d:a00:27ff:fe22:8301  prefixlen 64  scopeid 0x0<global>
        ether 08:00:27:22:83:01  txqueuelen 1000  (Ethernet)
        RX packets 110855  bytes 16897880 (16.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 131686  bytes 82851882 (79.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 2456806  bytes 463770856 (442.2 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2456806  bytes 463770856 (442.2 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 172.16.68.0  netmask 255.255.255.255
        tunnel   txqueuelen 1000  (IPIP Tunnel)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@master1 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    100    0        0 enp0s3
172.16.14.64    192.168.1.33    255.255.255.192 UG    0      0        0 tunl0
172.16.68.0     0.0.0.0         255.255.255.192 U     0      0        0 *
172.16.133.128  192.168.1.32    255.255.255.192 UG    0      0        0 tunl0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.1.0     0.0.0.0         255.255.255.0   U     100    0        0 enp0s3
[root@master1 ~]#

Now, we knows all the details, thus we can create our own NetworkAttachmentDefination file.

 

cat <<EOF | kubectl create -f -
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: macvlan-conf
spec:
  config: '{
      "cniVersion": "0.3.1",
      "type": "macvlan",
      "master": "enp0s3",
      "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"
      }
    }'
EOF

Post check of Multus CNI :

[root@master1 ~]# kubectl get network-attachment-definitions.k8s.cni.cncf.io macvlan-conf 
NAME           AGE
macvlan-conf   56s

[root@master1 ~]# kubectl describe network-attachment-definitions.k8s.cni.cncf.io macvlan-conf
Name:         macvlan-conf
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  k8s.cni.cncf.io/v1
Kind:         NetworkAttachmentDefinition
Metadata:
  Creation Timestamp:  2024-05-12T07:25:32Z
  Generation:          1
  Managed Fields:
    API Version:  k8s.cni.cncf.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:spec:
        .:
        f:config:
    Manager:         kubectl-create
    Operation:       Update
    Time:            2024-05-12T07:25:32Z
  Resource Version:  252464
  UID:               9e259bce-de62-4342-a13c-44807dc6113c
Spec:
  Config:  { "cniVersion": "0.3.0", "type": "macvlan", "master": "enp0s3", "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" } }
Events:    <none>

Pod configuration for Multus

 

cat <<EOF | kubectl create -f -
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
EOF

Let's check our newly created pod.
[root@master1 ~]#    kubectl get pods samplepod
NAME        READY   STATUS    RESTARTS   AGE
samplepod   1/1     Running   0          28s

It is in running condition. Now, we can identify the interfaces.

[root@master1 ~]#  kubectl exec -it samplepod -- /bin/sh
 / # ifconfig
eth0      Link encap:Ethernet  HWaddr A6:56:BC:E1:26:AC 
          inet addr:172.16.14.81  Bcast:0.0.0.0  Mask:255.255.255.255
          inet6 addr: fe80::a456:bcff:fee1:26ac/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1480  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1912 (1.8 KiB)  TX bytes:726 (726.0 B)
lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
net1      Link encap:Ethernet  HWaddr 6E:7B:C9:22:6F:B0 
          inet addr:192.168.1.200  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::6c7b:c9ff:fe22:6fb0/64 Scope:Link
          inet6 addr: 2401:4900:1c0a:4e0d:6c7b:c9ff:fe22:6fb0/64 Scope:Global
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:23 errors:0 dropped:0 overruns:0 frame:0
          TX packets:19 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1704 (1.6 KiB)  TX bytes:1554 (1.5 KiB)
/ #



Pod configuration for 2 Interfaces

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: samplepod2
  annotations:
    k8s.v1.cni.cncf.io/networks: macvlan-conf,macvlan-conf
spec:
  containers:
  - name: samplepod
    command: ["/bin/ash", "-c", "trap : TERM INT; sleep infinity & wait"]
    image: alpine
EOF

 

[root@master1 ~]# kubectl exec pods/samplepod2 -- ifconfig
eth0      Link encap:Ethernet  HWaddr EA:08:99:94:CD:45 
          inet addr:172.16.14.100  Bcast:0.0.0.0  Mask:255.255.255.255
          inet6 addr: fe80::e808:99ff:fe94:cd45/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1480  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1912 (1.8 KiB)  TX bytes:656 (656.0 B)
lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
net1      Link encap:Ethernet  HWaddr 0A:4F:D5:FB:85:9F 
          inet addr:192.168.1.201  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::84f:d5ff:fefb:859f/64 Scope:Link
          inet6 addr: 2401:4900:1c0a:4e0d:84f:d5ff:fefb:859f/64 Scope:Global
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:19 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1196 (1.1 KiB)  TX bytes:1506 (1.4 KiB)
net2      Link encap:Ethernet  HWaddr 2E:0D:1A:4E:15:59 
          inet addr:192.168.1.202  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: 2401:4900:1c0a:4e0d:2c0d:1aff:fe4e:1559/64 Scope:Global
          inet6 addr: fe80::2c0d:1aff:fe4e:1559/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:18 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1140 (1.1 KiB)  TX bytes:1512 (1.4 KiB)

If you want to support me, use my Paypal account.

Leave a Reply

Your email address will not be published. Required fields are marked *