For those of your who need more than one network interface for your PODs/Containers in Kubernetes. This document till go over a new extensibility framework called Multus, and a brief example of how I set it up.
What is Multus? Multus is a CNI network plugin for Kubernetes. It allows for attaching multiple network interfaces to pods in Kubernetes. There are alot of good reasons why you would want multiple networks interfaces for your pods, and not alot of good reasons why you shouldn't. Thanks for Intel for open sourcing this great technology!
In the following example, I'll go over a simple multus configuration to add an additional interface (called net1) to your PODs. For this you will need to create the following YAML files:
A simple Multus Setup
They very first thing we need to create is an adminpod. This will be used for customizing our kubernetes hosts that have been selected to run Multus. Essentially, we're dropping in a privledge daemonset pod, that will make modification to the underlying host configuration for Multus, then we'll remove it later. This will save you a few steps for manual changes, and it's a pretty cool thing to do! adminpod.yaml--- apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: adminpod-ds namespace: kube-system labels: tier: node app: adminpod spec: template: metadata: labels: tier: node app: adminpod spec: hostNetwork: true nodeSelector: role: gateway tolerations: - operator: Exists effect: NoSchedule volumes: - name: hostdoor hostPath: path: / type: Directory containers: - name: adminpod image: docker:5000/admincontainer:1.0.0.1 volumeMounts: - mountPath: /hostdoor name: hostdoor resources: requests: cpu: "100m" memory: "50Mi" limits: cpu: "100m" memory: "50Mi" command: ["/bin/bash", "-c", "sleep 2000000000000"] securityContext: privileged: truemultus-daemonset.yaml
--- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: network-attachment-definitions.k8s.cni.cncf.io spec: group: k8s.cni.cncf.io version: v1 scope: Namespaced names: plural: network-attachment-definitions singular: network-attachment-definition kind: NetworkAttachmentDefinition shortNames: - net-attach-def validation: openAPIV3Schema: properties: spec: properties: config: type: string --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: multus rules: - apiGroups: ["k8s.cni.cncf.io"] resources: - '*' verbs: - '*' - apiGroups: - "" resources: - pods - pods/status verbs: - get - update --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: multus roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: multus subjects: - kind: ServiceAccount name: multus namespace: kube-system --- apiVersion: v1 kind: ServiceAccount metadata: name: multus namespace: kube-system --- # ------------------------------------------------------ # Currently unused! # If you wish to customize, mount this in the # daemonset @ /usr/src/multus-cni/images/70-multus.conf # ------------------------------------------------------ kind: ConfigMap apiVersion: v1 metadata: name: multus-cni-config namespace: kube-system labels: tier: node app: multus data: cni-conf.json: | { "name": "multus-cni-network", "type": "multus", "delegates": [ { "type": "weave-net", "name": "weave-net.1", "delegate": { "isDefaultGateway": true } } ], "kubeconfig": "/etc/cni/net.d/multus.d/multus.kubeconfig" } # -------------- for openshift. # "delegates": [{ # "type": "openshift-sdn", # "name:" "openshift.1", # "masterplugin": true # }], --- apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: kube-multus-ds-amd64 namespace: kube-system labels: tier: node app: multus spec: template: metadata: labels: tier: node app: multus spec: hostNetwork: true tolerations: - operator: Exists effect: NoSchedule serviceAccountName: multus containers: - name: kube-multus image: nfvpe/multus:latest resources: requests: cpu: "100m" memory: "50Mi" limits: cpu: "100m" memory: "50Mi" securityContext: privileged: true volumeMounts: - name: cni mountPath: /host/etc/cni/net.d - name: cnibin mountPath: /host/opt/cni/bin volumes: - name: cni hostPath: path: /etc/cni/net.d - name: cnibin hostPath: path: /opt/cni/bin - name: multus-cfg configMap: name: multus-cni-confignetwork-crd.yaml
apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: network-attachment-definitions.k8s.cni.cncf.io spec: group: k8s.cni.cncf.io version: v1 scope: Namespaced names: plural: network-attachment-definitions singular: network-attachment-definition kind: NetworkAttachmentDefinition shortNames: - net-attach-def validation: openAPIV3Schema: properties: spec: properties: config: type: stringNext we need to setup the network mapping for our new interface. I'm mapping my hosts eth2 interfaces to net1 of the POD. The network assignment I choose is 10.40.40.0/24 which is another private network. macvlan-conf.yaml
apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: macvlan-conf spec: config: '{ "cniVersion": "0.3.0", "type": "macvlan", "master": "eth2", "mode": "bridge", "ipam": { "type": "host-local", "subnet": "10.40.40.0/24", "rangeStart": "10.40.40.1", "rangeEnd": "10.40.40.100", "routes": [ { "dst": "0.0.0.0/0" } ], "gateway": "" } }'Apply the following YAML configurations to K8S.
kubectl apply -f adminpod.yaml kubectl apply -f multus-daemonset.yml kubectl apply -f network-crd.yaml kubectl apply -f macvlan-conf.yamlUpdate the hosts you wish to deploy Multus on with this custom CNI configuration. I'm not running flannel, because I like weave-better. You'll need to make sure you are using weave-net.
MCONFIG_FILE=/hostdoor/etc/cni/net.d/1-multus-cni.conf echo "==> Deploying Weave Configuration for Multus backed Nodes" json=$'{\n name: node-cni-network,\n type: multus,\n kubeconfig: /etc/cni/net.d/multus.d/multus.kubeconfig,\n delegates: [{ \n type: weave-net,\n hairpinMode: true,\n masterplugin: true }]\n}\n' for pod in `kubectl get pod -n kube-system |grep adminpod|awk '{print $1}'`; do echo "==> Admin POD: ${pod}" kubectl -n kube-system exec ${pod} rm ${MCONFIG_FILE} kubectl -n kube-system exec ${pod} touch ${MCONFIG_FILE} echo "$json" kubectl -n kube-system exec ${pod} -t -- bash -c \ "echo '{' > ${MCONFIG_FILE}; \ echo ' \"name\": \"node-cni-network\",' >> ${MCONFIG_FILE}; \ echo ' \"type\": \"multus\",' >> ${MCONFIG_FILE}; \ echo ' \"kubeconfig\": \"/etc/cni/net.d/multus.d/multus.kubeconfig\",' >> ${MCONFIG_FILE}; \ echo ' \"delegates\": [{' >> ${MCONFIG_FILE}; \ echo ' \"type\": \"weave-net\",' >> ${MCONFIG_FILE}; \ echo ' \"hairpinMode\": true,' >> ${MCONFIG_FILE}; \ echo ' \"masterplugin\": true' >> ${MCONFIG_FILE}; \ echo ' }]' >> ${MCONFIG_FILE}; \ echo '}' >> ${MCONFIG_FILE};" doneOnce this is complete, you should be able to deploy a POD on those hosts running Multus, and they should have a secondary network interface called (net1). Validation
kubectl exec pod -i -t -- bash -il -c ifconfig -a eth0: flags=4163mtu 1376 inet 10.37.0.7 netmask 255.240.0.0 broadcast 10.47.255.255 inet6 fe80::8cfd:edff:fe83:d575 prefixlen 64 scopeid 0x20 ether 8e:fd:ed:83:d5:75 txqueuelen 0 (Ethernet) RX packets 26493 bytes 8412636 (8.0 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 55418 bytes 11906216 (11.3 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73 mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10 loop txqueuelen 1000 (Local Loopback) RX packets 711 bytes 163976 (160.1 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 711 bytes 163976 (160.1 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 net1: flags=4163 mtu 1500 inet 10.40.40.101 netmask 255.255.255.0 broadcast 0.0.0.0 inet6 fe80::8e5:cff:fe57:122e prefixlen 64 scopeid 0x20 ether 0a:e5:0c:57:12:2e txqueuelen 0 (Ethernet) RX packets 34138 bytes 8351448 (7.9 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 33548 bytes 8151748 (7.7 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0