Kubernetesの基本設計では一つのPodには一つのNICが提供され、外部からのアクセスや内部的な通信などを全てそのインターフェイスを経由して行います。
一方、KubernetesでMultus CNIを使うと、Podに対して複数のInterfaceを付与できます。 Multus CNIがセットアップされたクラスターでPodを作成すると、標準CNIによって一つのNICが割り当てられ、さらにNetwork Attachment Definitionによって定義したネットワークインターフェイスを使って、Podに別のインターフェイスを複数付与できます。

Multus CNIを使って、一つのVLANポートをPodに付与する
Multus CNIの使い方の一つに、Podに対してタグVLANを持つインターフェイスを追加する方法があるのですが、 赤帽ブログのMultusで遊ぶをみながらVLANモードでPodを作ったのですが、 こんな感じでエラーになり、うまくPodを作れませんでした。何か自分がこれまで設定した内容に間違いがあるのかもしれません。
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 19s default-scheduler Successfully assigned default/vlan-192.168.100.211 to ubuntu1 Warning FailedCreatePodSandBox 13s kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "d5ad4d8a9b98754120533bf9cf13c10c3ccecf0dd0f27b2c9d17d5abf14aaee8" network for pod "vlan-192.168.100.211": networkPlugin cni failed to set up pod "vlan-192.168.100.211_default" network: [default/vlan-192.168.100.211:vlan100-conf]: error adding container to network "vlan100-conf": failed to create vlan: file exists Normal SandboxChanged 6s (x2 over 12s) kubelet Pod sandbox changed, it will be killed and re-created. Warning FailedCreatePodSandBox 6s kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "748c54177de2a3b01e60167b34b1047b4147dd157078a6a47e95a429d639e46c" network for pod "vlan-192.168.100.211": networkPlugin cni failed to set up pod "vlan-192.168.100.211_default" network: [default/vlan-192.168.100.211:vlan100-conf]: error adding container to network "vlan100-conf": failed to create vlan: file exists Warning FailedCreatePodSandBox 0s kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "0bdf7ab44bf1aca3e699dbfec7dd0e729c47892f0c33b6732126a43eb5a18150" network for pod "vlan-192.168.100.211": networkPlugin cni failed to set up pod "vlan-192.168.100.211_default" network: [default/vlan-192.168.100.211:vlan100-conf]: error adding container to network "vlan100-conf": failed to create vlan: file exists
LinuxでタグVLANが必要な対向ノードと通信するにはVLAN用のインターフェイス設定ファイルを作る必要があり、今回はUbuntu 18.04を使っていたので次のような設定をしていました。
クラスターは enp30s0 のインターフェイスを使って動いています。ちなみに dhcp4: true になっていますが、 実際の環境は dhcp4: false に設定して固定のIPアドレスを設定しています。
$ sudo vi /etc/netplan/99-my-config.yaml
network:
ethernets:
enp16s0f0:
dhcp4: false
optional: true
enp16s0f1:
dhcp4: false
optional: true
enp30s0:
dhcp4: true
vlans:
vlan.100:
id: 100
link: enp16s0f0
addresses: [192.168.100.100/24]
vlan.200:
id: 200
link: enp16s0f1
addresses: [192.168.200.100/24]
version: 2
これを以下のように設定して再起動した以降はVLANモードによるPod作成がうまくいきました。
ちなみにNetplan.ioが利用されているUbuntuにおいては netplan apply コマンドでIPアドレスの設定が即時反映されますが、一度作成されたインターフェイスはそのコマンドでは削除されないため、ホストの再起動を行いました(再起動するまで同様のエラーが出てPodが作成できませんでした)。
$ sudo vi /etc/netplan/99-my-config.yaml
network:
ethernets:
enp16s0f0:
dhcp4: false
optional: true
enp16s0f1:
dhcp4: false
optional: true
enp30s0:
dhcp4: true
ホスト側でそれぞれのポートにVLANの設定がされてしまっていたので、Multus CNIがNetwork Attachment Definitionに従ってインターフェイスの設定をしようとしたらインターフェイスが使用中だったので「error adding container to network "vlan100-conf": failed to create vlan: file exists」というエラーを吐いていたようです。 サーバーにはタグVLANを設定したポートに繋いでおくだけで良かったようですね。
PodにPingを実施してみる
Podを作って、パケットが到達するか確認してみます。 基本的な設定は赤帽ブログのMultusで遊ぶの「vlanで追加ネットワークに接続」と同様にしています(違うのは標準CNIとしてCalicoを使っている点、インターフェイスとVLAN ID、IPアドレスくらいです)。
//Podを作る
# kubectl create -f vlan-pod1.yaml
//Podが作られたか確認
# kubectl get -f vlan-pod1.yaml
NAME READY STATUS RESTARTS AGE
vlan-192.168.100.211 1/1 Running 0 34m
//PodのIPアドレスを見てみる
# kubectl exec -it vlan-192.168.100.211 -- ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
3: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 2a:c9:40:80:79:d5 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.244.25.159/32 brd 10.244.25.159 scope global eth0
valid_lft forever preferred_lft forever
4: net1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 00:15:17:75:c0:8e brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.100.211/24 brd 192.168.100.255 scope global net1
valid_lft forever preferred_lft forever
//PodでtcpdumpをMultus CNIで追加したインターフェイス側で実行
# kubectl exec -it vlan-192.168.100.211 -- tcpdump -i net1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
//外部からpingを実行してみる(当然タグVLANが使える環境から)
$ ping -c3 192.168.100.211
//対向ノードからPodにpingを実行し、パケットがPodに到達するのを確認
//対向: 192.168.100.200 Pod: 192.168.100.211
# kubectl exec -it vlan-192.168.100.211 -- tcpdump -i net1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on net1, link-type EN10MB (Ethernet), capture size 262144 bytes
03:51:29.443436 IP 192.168.100.200 > vlan-192.168.100.211: ICMP echo request, id 29492, seq 0, length 64
03:51:29.443493 IP vlan-192.168.100.211 > 192.168.100.200: ICMP echo reply, id 29492, seq 0, length 64
03:51:30.038088 STP 802.1w, Rapid STP, Flags [Learn, Forward], bridge-id 8064.00:19:e8:93:31:40.8001, length 42
03:51:30.448592 IP 192.168.100.200 > vlan-192.168.100.211: ICMP echo request, id 29492, seq 1, length 64
03:51:30.448645 IP vlan-192.168.100.211 > 192.168.100.200: ICMP echo reply, id 29492, seq 1, length 64
03:51:31.452776 IP 192.168.100.200 > vlan-192.168.100.211: ICMP echo request, id 29492, seq 2, length 64
03:51:31.452829 IP vlan-192.168.100.211 > 192.168.100.200: ICMP echo reply, id 29492, seq 2, length 64
03:51:32.038198 STP 802.1w, Rapid STP, Flags [Learn, Forward], bridge-id 8064.00:19:e8:93:31:40.8001, length 42
Multus CNIを使って、複数のVLANポートをPodに付与する
複数のVLANポートをPodに付与するには、もう一つNetwork Attachment Definitionを作って...
# kubectl get network-attachment-definition NAME AGE vlan100-conf 98m vlan200-conf 82s
次のように複数のインターフェイスを指定したPod YAMLを作って作成すれば良いようです。
# cat vlan-pod-multi.yaml
---
apiVersion: v1
kind: Pod
metadata:
# generateName: vlan-
name: vlan-multi
labels:
app: multus-vlan
annotations:
k8s.v1.cni.cncf.io/networks: '[
{ "name": "vlan100-conf",
"ips": [ "192.168.100.211/24" ]
},
{
"name": "vlan200-conf",
"ips": [ "192.168.200.211/24" ]
}
]'
spec:
containers:
- name: centos-tools
image: docker.io/centos/tools:latest
command:
- /sbin/init
securityContext:
privileged: true
それぞれのIPアドレスに対してPingが通るはずです。
$ ping -c1 192.168.100.211 PING 192.168.100.211 (192.168.100.211): 56 data bytes 64 bytes from 192.168.100.211: icmp_seq=0 ttl=64 time=0.669 ms --- 192.168.100.211 ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.669/0.669/0.669/0.000 ms $ ping -c1 192.168.200.211 PING 192.168.200.211 (192.168.200.211): 56 data bytes 64 bytes from 192.168.200.211: icmp_seq=0 ttl=64 time=0.832 ms --- 192.168.200.211 ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.832/0.832/0.832/0.000 ms
以上は次の構成で確認した内容です。
- Kubernetes 1.20.2
- Calico 3.16.6
- Multus CNI 3.6