Multusを試す

# Multus CNIって？
MultusはPodに複数のネットワークインタフェースをアタッチ可能とするCNIプラグインです。Multus自体が複数インタフェースを利用可能なCNIだと勘違いしていましたが、複数のCNIを同時に利用可能とするためのメタCNIプラグインとして稼働するようです。Multus自体、ハイパフォーマンスを要求される通信事業者向けコンテナアプリケーションで、サービス系、管理系のネットワークインターフェースを分離するような目的で使われることが多いようなので、私も通信事業者に務めるエンジニアの端くれとして、Multusのクイックスタートガイドを参考に簡単に動きを確認してみようと思います。

## 手順概要
1. 準備
2. MutlusバイナリのインストールとDaemonsetのデプロイ
3. 追加ネットワークインタフェース用CustomResourceDefinition(NetworkAttachmentDefinition）の作成
4. 複数NICをアタッチしたPodの作成
5. 確認

## 1. 準備
確認した環境はVMware社のK8SディストリビューションであるTanzu kubernetes Gridです。worker2台構成で、各workerノードにはeth0、eth1の2つのNICを接続しています。

```
$ kubectl get node
NAME                        STATUS   ROLES    AGE    VERSION
tkc18-control-plane-j2twb   Ready    master   115m   v1.19.1+vmware.2
tkc18-md-0-988884c8-95z7v   Ready    <none>   114m   v1.19.1+vmware.2
tkc18-md-0-988884c8-k5j9p   Ready    <none>   114m   v1.19.1+vmware.2
```

## 2. MutlusバイナリのインストールとDaemonsetのデプロイ
まずMultusバイナリをインストールし、Multusを使用するための設定を行うDaemonsetをデプロイします。Daemonsetによって、各ノード上へのMultusバイナリの配置、設定ファイルの作成、Multusがk8s APIにアクセスするための認証情報の配置などが実行されるようです。

```
$ git clone https://github.com/intel/multus-cni.git && cd multus-cni
$ cat ./images/multus-daemonset.yml | kubectl apply -f -
$ kubectl get pods --all-namespaces | grep -i multus
kube-system   kube-multus-ds-amd64-pdx88                          1/1     Running            0          94m
kube-system   kube-multus-ds-amd64-pq28r                          1/1     Running            0          94m
kube-system   kube-multus-ds-amd64-r8kn9                          1/1     Running            0          94m
```

## 3. 追加ネットワークインタフェース用CustomResourceDefinition(NetworkAttachmentDefinition）の作成
次にPodに接続される追加ネットワークインタフェースを定義するCustom Resource Definition（Network Resource Definition）を作成します。
今回はクイックスタートガイドの通り、macvlanを利用、利用するインタフェースはeth1、IPAMについてはとりあえず試すだけだったのでStatic設定としています。

```
$ cat <<EOF | kubectl create -f -
> apiVersion: "k8s.cni.cncf.io/v1"
> kind: NetworkAttachmentDefinition
> metadata:
>   name: macvlan-conf
> spec:
>   config: '{
>             "cniVersion": "0.3.1",
>             "plugins": [
>                 {
>                     "type": "macvlan",
>                     "capabilities": { "ips": true },
>                     "master": "eth1",
>                     "mode": "bridge",
>                     "ipam": {
>                         "type": "static"
>                     }
>                 }, {
>                     "capabilities": { "mac": true },
>                     "type": "tuning"
>                 } ]
>         }'
> EOF
$ kubectl get network-attachment-definitions
NAME           AGE
macvlan-conf   85m
$ kubectl describe network-attachment-definitions macvlan-conf
Name:         macvlan-conf
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  k8s.cni.cncf.io/v1
Kind:         NetworkAttachmentDefinition
Metadata:
  Creation Timestamp:  2020-12-06T07:27:19Z
  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:            2020-12-06T07:27:19Z
  Resource Version:  10002
  Self Link:         /apis/k8s.cni.cncf.io/v1/namespaces/default/network-attachment-definitions/macvlan-conf
  UID:               f5520a94-6401-401f-a1d9-5c57d5f2393f
Spec:
  Config:  { "cniVersion": "0.3.1", "plugins": [ { "type": "macvlan", "capabilities": { "ips": true }, "master": "eth1", "mode": "bridge", "ipam": { "type": "static" } }, { "capabilities": { "mac": true }, "type": "tuning" } ] }
Events:    <none>
$
```

## 4. 複数NICをアタッチしたPodの作成
annotationで追加ネットワークインタフェースに関する記述を記載し、デプロイします。

```
$ cat <<EOF | kubectl create -f -
> apiVersion: v1
> kind: Pod
> metadata:
>   name: samplepod1
>   annotations:
>     k8s.v1.cni.cncf.io/networks: '[
>             {
>               "name": "macvlan-conf",
>               "ips": [ "192.168.3.201/24" ]
>             }
>     ]'
> spec:
>   containers:
>   - name: centos-tools
>     image: docker.io/centos/tools:latest
>     command:
>     - /sbin/init
>   nodeSelector:
>     type: node1
> EOF
$ cat <<EOF | kubectl create -f -
> apiVersion: v1
> kind: Pod
> metadata:
>   name: samplepod4
>   annotations:
>     k8s.v1.cni.cncf.io/networks: '[
>             {
>               "name": "macvlan-conf",
>               "ips": [ "192.168.3.204/24" ]
>             }
>     ]'
> spec:
>   containers:
>   - name: centos-tools
>     image: docker.io/centos/tools:latest
>     command:
>     - /sbin/init
>   nodeSelector:
>     type: node2
> EOF
```

## 5. 確認
デプロイ後、別々の物理インターフェースに紐付いたNICが２つPodに接続されており、Pingによる疎通性も確認できました（不要な出力は削除しています）。

```
$ kubectl exec -it samplepod1 -- ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
3: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    inet 100.96.1.4/24 brd 100.96.1.255 scope global eth0
4: net1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    inet 192.168.3.201/24 brd 192.168.3.255 scope global net1

$ kubectl exec -it samplepod4 -- ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
3: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    inet 100.96.2.7/24 brd 100.96.2.255 scope global eth0
4: net1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    inet 192.168.3.204/24 brd 192.168.3.255 scope global net1

$ kubectl exec -it samplepod1 -- ping 192.168.3.204
PING 192.168.3.204 (192.168.3.204) 56(84) bytes of data.
64 bytes from 192.168.3.204: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 192.168.3.204: icmp_seq=2 ttl=64 time=0.042 ms

$ kubectl exec -it samplepod1 -- ping 100.96.2.7
PING 100.96.2.7 (100.96.2.7) 56(84) bytes of data.
64 bytes from 100.96.2.7: icmp_seq=1 ttl=62 time=1.76 ms
64 bytes from 100.96.2.7: icmp_seq=2 ttl=62 time=0.916 ms
```
ほぼクイックスタートガイドの通りに実行するだけでMultiNIC構成が出来上がりますので、試すだけなら非常に簡単です。ただしプロダクション利用となると色々な考慮が必要となるため、しっかりとした検証が必要になります。時間見つけて深堀りしてみたいと思います。

##　参照したサイト
https://github.com/intel/multus-cni