Multus CNIを試してみる
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をインストールしなくても提供されます。
実際、このディフォルトの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アドレス重複が起きます。このため、単にDeployment
やStafulSet
等でスケーリングだけでIPアドレスの資源管理が難しく、管理方法を別途検討するか、外部にDHCPサーバを建てる必要があります。
(このIssueではglobal IPAMが可能な記載がありましたが、手前の環境ではダメでした。他の条件もありそうなのでコードを見てみます。)
static
については現時点の最新版(v0.8.6)では使えませんでした。(CNIが無いと怒られるんですがhost-local
指定にしておいてPODのManifest側で設定すれば同じことが出来そうです。)
spec.containers.securityContext.privileged
をtrue
を設定するとSecondary IPを付与できます。
ちなみに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
次にこの状態のまま以下でNetworkAttachmentDefinition
のmacvlan
の設定を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