Skip to content

Instantly share code, notes, and snippets.

@tomotake-koike
Created July 8, 2020 04:03
Show Gist options
  • Select an option

  • Save tomotake-koike/815fdd3fd2909e98cda859814940efa7 to your computer and use it in GitHub Desktop.

Select an option

Save tomotake-koike/815fdd3fd2909e98cda859814940efa7 to your computer and use it in GitHub Desktop.
Multusを試して分かったことを記載しています。

Multusのフィジビリティスタディ

Multusは2つ以上のCNIのNetwork InterfaceをなんとかPODへアタッチする仕組みで、肝心なところは基本的に連携するCNIに依存し、IP Address Management(IPAM)もCNIに頼る思想です。
一方で、一般的にCNIが提供されていないNodeの物理NICにつないでいくために以下のPluginが用意されており、別途CNIを用意しなくてもMultus CRDをインストールする手順を実行すると利用可能となります。このためか、一般的なMultusに関するBlog等を見るとこのPluginを見て「Multus=2つ目のNICを使う仕組み」と強調されてる気がしますが、異なる特徴の複数CNI(SR-IOV CNIなど)を取り入れる仕組みとしての利用として考えたほうが良いかもしれません。ただ、取り込むCNI(特にIPAM)がIPAM含め対応している必要ががありそうです。(calicoはいまのところうまくいってません。)それと、K8s Serviceとの連携もいまのところ難しいです。

  • bridge: Creates a bridge, adds the host and the container to it.
  • ipvlan: Adds an ipvlan interface in the container.
  • loopback: Set the state of loopback interface to up.
  • macvlan: Creates a new MAC address, forwards all traffic to that to the container.
  • ptp: Creates a veth pair.
  • vlan: Allocates a vlan device.
  • host-device: Move an already-existing device into a container.

これ以外にflannelのinterfaceを付与するPluginだけは別途Flannelをインストールしなくても提供されます。

https://github.com/containernetworking/plugins

実際、このディフォルトのPluginと連携する以下IPAM Configが用意されていますが、(いまのところ)貧弱でProductionユースには用途が限定されるものと思われます。

  • dhcp: Runs a daemon on the host to make DHCP requests on behalf of the container
  • host-local: Maintains a local database of allocated IPs
  • static: Allocate a static IPv4/IPv6 addresses to container and it's useful in debugging purpose.

認識しておかないといけないポイントとして、これらのIPAMは一般的なIPAM-CNIのようにCluster wideで連携してくれるものではありません。host-localに至ってはNode毎にIPアドレスの資源管理をするため、Cluster wideで設定を入れておくと(NetworkAttachmentDefinitionリソース)複数NodeでPODを生成するとIPアドレス重複が起きます。このため、単にDeploymentStafulSet等でスケーリングだけでIPアドレスの資源管理が難しく、管理方法を別途検討するか、外部にDHCPサーバを建てる必要があります。
このIssueではglobal IPAMが可能な記載がありましたが、手前の環境ではダメでした。他の条件もありそうなのでコードを見てみます。)
staticについては現時点の最新版(v0.8.6)では使えませんでした。(CNIが無いと怒られるんですがhost-local指定にしておいてPODのManifest側で設定すれば同じことが出来そうです。)

ちなみにPod内のWorkload側でSecondary IPを付与したりすることは権限上出来ませんでした。(Priviledgeの設定をうまくやるといけるのかも?)


動作検証 その1

以下3つのInterfaceを付与したPODをDeploymentで3POD生成してみます。

  • calico(ディフォルトのCNI)
  • flannel #1
  • flannel #2
  • macvlan

macvlanのIPAMはhost-localとするため各NodeにIP rangeの設定を入れています。

network-attachment-definitions.k8s.cni.cncf.ioのリソース生成

flannelは以下でCluster wideのIPAMを設定が可能です。

kubectl apply -f - << EOF
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: vlan-conf
spec:
  config: '{
            "cniVersion": "0.3.1",
            "plugins": [
          {
            "type": "flannel",
            "delegate": {
              "hairpinMode": true,
              "isDefaultGateway": true
            }
          },
          {
            "type": "portmap",
            "capabilities": {"portMappings": true},
            "snat": true
          }
              ]
        }'
EOF

macvlanのConfigは各Nodeで設定するためspec.configは空になっています。

kubectl apply -f - << EOF
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: macvlan-conf
EOF

各NodeにIP rangeを設定

1つのNodeで以下を設定。

mkdir -p /etc/cni/multus/net.d/
cat <<EOF > /etc/cni/multus/net.d/macvlan.conf
{
  "cniVersion": "0.3.0",
  "type": "macvlan",
  "name": "macvlan-conf",
  "master": "enp6s0",
  "mode": "bridge",
  "ipam": {
      "type": "host-local",
      "ranges": [
          [ {
               "subnet": "172.16.1.0/24",
               "rangeStart": "172.16.1.100",
               "rangeEnd": "172.16.1.149"
          } ]
      ]
  }
}
EOF

もう1つのNodeで以下を設定。

mkdir -p /etc/cni/multus/net.d/
cat <<EOF > /etc/cni/multus/net.d/macvlan.conf
{
  "cniVersion": "0.3.0",
  "type": "macvlan",
  "name": "macvlan-conf",
  "master": "enp6s0",
  "mode": "bridge",
  "ipam": {
      "type": "host-local",
      "ranges": [
          [ {
               "subnet": "172.16.1.0/24",
               "rangeStart": "172.16.1.150",
               "rangeEnd": "172.16.1.199"
          } ]
      ]
  }
}
EOF

Deploymentをapply

自前のチェック用のContainerを生成しています。

kubectl apply -f - << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ncurl-multus
  labels:
    app: ncurl-multus
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ncurl-multus
  template:
    metadata:
      labels:
        app: ncurl-multus
      annotations:
        k8s.v1.cni.cncf.io/networks: vlan-conf, vlan-conf, macvlan-conf
    spec:
      containers:
      - name: ncurl-multul
        image: tomotake/ubuntu-ncurl:latest
        command: ["bash"]
        args: ["-c", "mknod -m 777 fifo p ; while true ; do cat fifo | nc -v -t -k -l 30000 | tee fifo ; done"]
        ports:
        - containerPort: 30000
          protocol: TCP
          name: tcp-test-0
        readinessProbe:
          tcpSocket:
            port: 30000
          failureThreshold: 1
          periodSeconds: 1
EOF

生成したPodのIF確認

以下のように2つのNodeにまたがって生成されました。

$ kubectl get po -o wide -l app=ncurl-multus
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE       NOMINATED NODE   READINESS GATES
ncurl-multus-785bf987d7-q4xxw   1/1     Running   0          2m43s   172.16.188.244   ubu05-01   <none>           <none>
ncurl-multus-785bf987d7-rrnpk   1/1     Running   0          2m43s   172.16.253.176   ubu05-02   <none>           <none>
ncurl-multus-785bf987d7-sxn2f   1/1     Running   0          2m43s   172.16.189.4     ubu05-01   <none>           <none>

この結果こんな感じにNW IFが付与されています。

$ for p in $( kubectl get po -l app=ncurl-multus -o name) ; do kubectl exec $p -- hostname ; kubectl exec $p -- ip a | grep inet\  ; done 
ncurl-multus-785bf987d7-q4xxw
    inet 127.0.0.1/8 scope host lo
    inet 172.16.188.244/32 scope global eth0
    inet 10.244.0.80/24 scope global net1
    inet 10.244.0.81/24 scope global net2
    inet 172.16.1.100/24 scope global net3
ncurl-multus-785bf987d7-rrnpk
    inet 127.0.0.1/8 scope host lo
    inet 172.16.253.176/32 scope global eth0
    inet 10.244.0.72/24 scope global net1
    inet 10.244.0.73/24 scope global net2
    inet 172.16.1.150/24 scope global net3
ncurl-multus-785bf987d7-sxn2f
    inet 127.0.0.1/8 scope host lo
    inet 172.16.189.4/32 scope global eth0
    inet 10.244.0.82/24 scope global net1
    inet 10.244.0.83/24 scope global net2
    inet 172.16.1.101/24 scope global net3

動作検証 その2

次にこの状態のまま以下でNetworkAttachmentDefinitionmacvlanの設定をcluster wideの設定で入れ、POD側で固定IPアドレスの設定を行います。
NetworkAttachmentDefinition側のIPAM設定でIP rangeを指定していますが、この指定がなかったりこのrangeから外れたIPアドレスをPODに生成しようとしてもContainerCreating状態で止まってしまいます。

kubectl apply -f - << EOF
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: macvlan-conf
spec:
  config: '{
            "cniVersion": "0.3.1",
            "plugins": [
                {
                    "type": "macvlan",
                    "master": "enp6s0",
                    "capabilities": { "ips": true },
                    "ipam": {
                      "type": "host-local",
                      "subnet": "172.16.1.0/24",
                      "rangeStart": "172.16.1.200",
                      "rangeEnd": "172.16.1.246",
                      "routes": [
                      { "dst": "0.0.0.0/0" }
                      ],
                      "gateway": "172.16.1.1"
                    }
                }, {
                    "capabilities": { "mac": true },
                    "type": "tuning"
                } ]
        }'
EOF

IPアドレス固定のPOD生成

以下、複数のNW IFを付与したPODを生成してみます。

  • calico(ディフォルトのCNI)
  • flannel #1
  • flannel #2
  • macvlan
  • macvlan(固定IPアドレス指定)

IPアドレスを固定指定しているので、Deploymentですがreplicas: 1になっています。

kubectl apply -f - << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ncurl-multus-2
  labels:
    app: ncurl-multus-2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ncurl-multus-2
  template:
    metadata:
      labels:
        app: ncurl-multus-2
      annotations:
        k8s.v1.cni.cncf.io/networks: '[
          { "name": "vlan-conf" },
          { "name": "vlan-conf" }, 
          { "name": "macvlan-conf" },
          { "name": "macvlan-conf",
            "ips": [ "172.16.1.201" ]}
        ]'        
    spec:
      containers:
      - name: ncurl-multus
        image: tomotake/ubuntu-ncurl:latest
        command: ["bash"]
        args: ["-c", "mknod -m 777 fifo p ; while true ; do cat fifo | nc -v -t -k -l 30000 | tee fifo ; done"]
        ports:
        - containerPort: 30000
          protocol: TCP
          name: tcp-test-0
        readinessProbe:
          tcpSocket:
            port: 30000
          failureThreshold: 1
          periodSeconds: 1

生成したPodのIF確認

IP rangeの設定(172.16.1.150-199)が残っているNodeでPODが生成されています。

tomotake@ubu05-00:~/multus-test$ kubectl get po -l app=ncurl-multus-2 -o wide
NAME                              READY   STATUS    RESTARTS   AGE   IP               NODE       NOMINATED NODE   READINESS GATES
ncurl-multus-2-848bfd457c-d7wlk   1/1     Running   0          46m   172.16.253.173   ubu05-02   <none>           <none>

固定したIPアドレスが付与されいます。

$ for p in $( kubectl get po -l app=ncurl-multus-2 -o name) ; do kubectl exec $p -- hostname ; kubectl exec $p -- ip a | grep inet\  ; done
ncurl-multus-2-848bfd457c-d7wlk                                              
    inet 127.0.0.1/8 scope host lo                                                                                                           
    inet 172.16.253.173/32 scope global eth0                                                                                        
    inet 10.244.0.66/24 scope global net1                                                                                           
    inet 10.244.0.67/24 scope global net2
    inet 172.16.1.211/24 scope global net3
    inet 172.16.1.201/24 scope global net4

追加の確認としてNodeにIP rangeの設定を残したまま先程の確認で使用したPODのをdeleteして再生成させIPAMのIPアドレス自動割り当ての挙動を確認しました。
IPAMhost-localの場合、Node側のIP rangeの設定よりCluster wide側の設定が優先的に扱われているようです。

$ kubectl get po -l app=ncurl-multus -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE       NOMINATED NODE   READINESS GATES
ncurl-multus-785bf987d7-6kj2z   1/1     Running   0          2m16s   172.16.253.177   ubu05-02   <none>           <none>
ncurl-multus-785bf987d7-9lgr2   1/1     Running   0          2m15s   172.16.189.5     ubu05-01   <none>           <none>
ncurl-multus-785bf987d7-q2fjj   1/1     Running   0          2m15s   172.16.253.178   ubu05-02   <none>           <none>

しかもIPアドレス重複が発生してしまっている状態になっていました。

$ for p in $( kubectl get po -l app=ncurl-multus -o name) ; do kubectl exec $p -- hostname ; kubectl exec $p -- ip a | grep inet\  ; done
ncurl-multus-785bf987d7-6kj2z
    inet 127.0.0.1/8 scope host lo
    inet 172.16.253.177/32 scope global eth0
    inet 10.244.0.74/24 scope global net1
    inet 10.244.0.75/24 scope global net2
    inet 172.16.1.200/24 scope global net3
ncurl-multus-785bf987d7-9lgr2
    inet 127.0.0.1/8 scope host lo
    inet 172.16.189.5/32 scope global eth0
    inet 10.244.0.84/24 scope global net1
    inet 10.244.0.85/24 scope global net2
    inet 172.16.1.200/24 scope global net3
ncurl-multus-785bf987d7-q2fjj
    inet 127.0.0.1/8 scope host lo
    inet 172.16.253.178/32 scope global eth0
    inet 10.244.0.76/24 scope global net1
    inet 10.244.0.77/24 scope global net2
    inet 172.16.1.202/24 scope global net3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment