通常、kubernetesでPod環境を作成する際には、Kubeletが、CRIを活用して、Pod用Sandboxコンテナを生成します。
そして、Sandboxコンテナに割り当てられたNetwork Namespaceに、Pod環境として動作できるように、CNI Pluginを活用して、IPアドレスが付与されます。
- Architecture of The CRI Plugin より引用 -
今回は、CNI Pluginを活用してIPAM動作を確認してみます。
ちなみに、kubernetes環境は、一切、使用しないのであしからず。。
■ CNIとは?
CNI(Container Network Interface)では、Linuxコンテナでネットワークインターフェイスを構成するプラグインを作成するための仕様とプラグインが活用されています。
ちなみに、これらの動作概要については、こちらのBlog記事が参考になりました。
- マルチホストでのDocker Container間通信 第3回: Kubernetesのネットワーク(CNI, kube-proxy, kube-dns)
- How a Kubernetes Pod Gets an IP Address
詳細を確認したい場合には、こちらが参考になります。
■ CNI Plugin環境整備
以下、手持ちのLinux環境を使って、簡単な動作確認を行っています。
(1) Linux環境
- OSバージョン: Ubuntu 16.04.1 LTS
- Go Version: go1.15 linux/amd64
(2) CNI Plugin環境セットアップ
gitリポジトリ: containernetworking/pluginsから、ソースファイルを入手します
なお、以降の基本操作は、全て、rootユーザで行うものとします
# cd $HOME
# git clone https://github.com/containernetworking/plugins.git
# cd plugins
# git checkout -b v0.9.0 v0.9.0
Switched to a new branch 'v0.9.0'
手動で、Pluginコマンドのビルドを行います
# ./build_linux.sh
Building plugins
bandwidth
firewall
flannel
portmap
sbr
tuning
vrf
bridge
host-device
ipvlan
loopback
macvlan
ptp
vlan
dhcp
host-local
static
CNI Pluginバイナリファイルが作成できたことを確認しておきます
# ls -l /root/plugins/bin
total 72620
-rwxr-xr-x 1 root root 4175439 Jan 14 09:12 bandwidth
-rwxr-xr-x 1 root root 4547099 Jan 14 09:12 bridge
-rwxr-xr-x 1 root root 10338275 Jan 14 09:12 dhcp
-rwxr-xr-x 1 root root 4811536 Jan 14 09:12 firewall
-rwxr-xr-x 1 root root 3365183 Jan 14 09:12 flannel
-rwxr-xr-x 1 root root 4155129 Jan 14 09:12 host-device
-rwxr-xr-x 1 root root 3584921 Jan 14 09:12 host-local
-rwxr-xr-x 1 root root 4307875 Jan 14 09:12 ipvlan
-rwxr-xr-x 1 root root 3546106 Jan 14 09:12 loopback
-rwxr-xr-x 1 root root 4382656 Jan 14 09:12 macvlan
-rwxr-xr-x 1 root root 3981546 Jan 14 09:12 portmap
-rwxr-xr-x 1 root root 4482408 Jan 14 09:12 ptp
-rwxr-xr-x 1 root root 3716713 Jan 14 09:12 sbr
-rwxr-xr-x 1 root root 3168905 Jan 14 09:12 static
-rwxr-xr-x 1 root root 3687960 Jan 14 09:12 tuning
-rwxr-xr-x 1 root root 4303412 Jan 14 09:12 vlan
-rwxr-xr-x 1 root root 3775552 Jan 14 09:12 vrf
(3) CNIツール環境セットアップ
CNIツールをインストールします
# go get github.com/containernetworking/cni/cnitool
CNIツールが動作できることを確認しておきます
# cnitool
cnitool: Add, check, or remove network interfaces from a network namespace
cnitool add <net> <netns>
cnitool check <net> <netns>
cnitool del <net> <netns>
(4) CNI用コンフィグレーションファイルの配置
CNI Pluginを呼び出して、"bridge"->"ipam"のパイプラインが動作できるようにコンフィグファイルを配置しておきます
{
"cniVersion": "0.4.0",
"name": "mynet",
"type": "bridge",
"bridge": "mybridge",
"isDefaultGateway": true,
"ipam": {
"type": "host-local",
"subnet": "192.168.100.0/24"
}
}
■ 実際に、CNIツールを動かしてみる
CNI Pluginを呼び出して、"bridge"->"ipam"のパイプライン動作によって、Netnetwork namespaceにIPアドレスが割り当てられる様子を確認してみます
(1) 初期状態の確認
Network namespaceが存在していないことを確認しておく
# ip netns
Linux Bridgeが存在していないことを確認しておく
# brctl show | grep mybridge
(2) テスト用Network namespaceの作成
手作業で、Network namespaceを作成します
# ip netns add testing1
# ip netns add testing2
# ip netns add testing3
Network namespaceが3個、作成されていることを確認しておきます
# ip netns
testing3
testing2
testing1
(3) CNIツールを動かして、IPアドレスを割り当てる
"testing1"ネームスペースでの作業
まずは、"testing1"ネームスペースに、IPアドレスを割り当てます
# CNI_PATH=/root/plugins/bin cnitool add mynet /var/run/netns/testing1
{
"cniVersion": "0.4.0",
"interfaces": [
{
"name": "mybridge",
"mac": "3e:af:39:a3:b4:93"
},
{
"name": "veth0820d945",
"mac": "96:8b:02:29:7a:84"
},
{
"name": "eth0",
"mac": "e2:ab:88:4c:67:2d",
"sandbox": "/var/run/netns/testing1"
}
],
"ips": [
{
"version": "4",
"interface": 2,
"address": "192.168.100.2/24",
"gateway": "192.168.100.1"
}
],
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "192.168.100.1"
}
],
"dns": {}
"testing1"ネームスペースの”eth0”のネットワークインタフェースに割り当てられたIPアドレスを確認します
-> ”192.168.100.2/24”が付与されています
# ip netns exec testing1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: eth0@if5404: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether e2:ab:88:4c:67:2d brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.100.2/24 brd 192.168.100.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::e0ab:88ff:fe4c:672d/64 scope link
valid_lft forever preferred_lft forever
Linux Bridgeの様子も確認しておきます
-> mybridgeが新たに作成されて、”veth0820d945”が接続されています
# brctl show
bridge name bridge id STP enabled interfaces
... (snip)
mybridge 8000.3eaf39a3b493 no veth0820d945
"testing2"ネームスペースでの作業
まずは、"testing2"ネームスペースに、IPアドレスを割り当てます
# CNI_PATH=/root/plugins/bin cnitool add mynet /var/run/netns/testing2
{
"cniVersion": "0.4.0",
"interfaces": [
{
"name": "mybridge",
"mac": "3e:af:39:a3:b4:93"
},
{
"name": "vethdc29b15e",
"mac": "76:59:67:9d:1a:14"
},
{
"name": "eth0",
"mac": "e2:55:2e:09:ad:75",
"sandbox": "/var/run/netns/testing2"
}
],
"ips": [
{
"version": "4",
"interface": 2,
"address": "192.168.100.3/24",
"gateway": "192.168.100.1"
}
],
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "192.168.100.1"
}
],
"dns": {}
"testing2"ネームスペースの”eth0”のネットワークインタフェースに割り当てられたIPアドレスを確認します
-> ”192.168.100.3/24”が付与されています
# ip netns exec testing2 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: eth0@if5405: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether e2:55:2e:09:ad:75 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.100.3/24 brd 192.168.100.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::e055:2eff:fe09:ad75/64 scope link
valid_lft forever preferred_lft forever
Linux Bridgeの様子も確認しておきます
-> mybridgeに、”vethdc29b15e”が接続されています
# brctl show
bridge name bridge id STP enabled interfaces
... (snip)
mybridge 8000.3eaf39a3b493 no veth0820d945
vethdc29b15e
"testing3"ネームスペースでの作業
まずは、"testing3"ネームスペースに、IPアドレスを割り当てます
# CNI_PATH=/root/plugins/bin cnitool add mynet /var/run/netns/testing3
{
"cniVersion": "0.4.0",
"interfaces": [
{
"name": "mybridge",
"mac": "3e:af:39:a3:b4:93"
},
{
"name": "vethc3a9e0b8",
"mac": "16:f9:fd:71:5e:a0"
},
{
"name": "eth0",
"mac": "6e:f8:3d:da:f0:bb",
"sandbox": "/var/run/netns/testing3"
}
],
"ips": [
{
"version": "4",
"interface": 2,
"address": "192.168.100.4/24",
"gateway": "192.168.100.1"
}
],
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "192.168.100.1"
}
],
"dns": {}
"testing3"ネームスペースの”eth0”のネットワークインタフェースに割り当てられたIPアドレスを確認します
-> ”192.168.100.4/24”が付与されています
# ip netns exec testing3 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: eth0@if5406: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 6e:f8:3d:da:f0:bb brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.100.4/24 brd 192.168.100.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::6cf8:3dff:feda:f0bb/64 scope link
valid_lft forever preferred_lft forever
Linux Bridgeの様子も確認しておきます
-> mybridgeに、”vethc3a9e0b8”が接続されています
# brctl show
bridge name bridge id STP enabled interfaces
... (snip)
mybridge 8000.3eaf39a3b493 no veth0820d945
vethc3a9e0b8
vethdc29b15e
(4) 実際に、Namespace間での疎通性を確認しておく
"testing1"ネームスペースから、"testing2"にpingを打ってみます
# ip netns exec testing1 ping -I 192.168.100.2 192.168.100.3
PING 192.168.100.3 (192.168.100.3) from 192.168.100.2 : 56(84) bytes of data.
64 bytes from 192.168.100.3: icmp_seq=1 ttl=64 time=0.169 ms
64 bytes from 192.168.100.3: icmp_seq=2 ttl=64 time=0.141 ms
64 bytes from 192.168.100.3: icmp_seq=3 ttl=64 time=0.155 ms
64 bytes from 192.168.100.3: icmp_seq=4 ttl=64 time=0.157 ms
64 bytes from 192.168.100.3: icmp_seq=5 ttl=64 time=0.156 ms
^C
--- 192.168.100.3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 3998ms
rtt min/avg/max/mdev = 0.141/0.155/0.169/0.016 ms
"testing1"ネームスペースから、"testing3"にpingを打ってみます
# ip netns exec testing1 ping -I 192.168.100.2 192.168.100.4
PING 192.168.100.4 (192.168.100.4) from 192.168.100.2 : 56(84) bytes of data.
64 bytes from 192.168.100.4: icmp_seq=1 ttl=64 time=0.263 ms
64 bytes from 192.168.100.4: icmp_seq=2 ttl=64 time=0.131 ms
64 bytes from 192.168.100.4: icmp_seq=3 ttl=64 time=0.154 ms
64 bytes from 192.168.100.4: icmp_seq=4 ttl=64 time=0.156 ms
64 bytes from 192.168.100.4: icmp_seq=5 ttl=64 time=0.154 ms
^C
--- 192.168.100.4 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 3998ms
rtt min/avg/max/mdev = 0.131/0.171/0.263/0.048 ms
■ CNI Pluginの挙動の振り返り
CNI Pluginを呼び出して、"bridge"->"ipam"のパイプライン動作によって、Netnetwork namespaceにIPアドレスが割り当てられましたので、その結果を、振り返っておきます。
(1) /var/lib/cni/networks/mynet
# ls -l /var/lib/cni/networks/mynet
total 16
-rw-r--r-- 1 root root 34 Jan 14 09:58 192.168.100.2
-rw-r--r-- 1 root root 34 Jan 14 10:11 192.168.100.3
-rw-r--r-- 1 root root 34 Jan 14 10:15 192.168.100.4
-rw-r--r-- 1 root root 13 Jan 14 10:15 last_reserved_ip.0
-rwxr-x--- 1 root root 0 Jan 11 12:31 lock
cnitool-49346948b0d506e05f2d
cnitool-256083c5997e421f082a
cnitool-c11ae72283507a6e6b3c
192.168.100.4
(2) /var/lib/cni/results
# ls -l /var/lib/cni/results
total 12
-rw------- 1 root root 763 Jan 14 10:11 mynet-cnitool-256083c5997e421f082a-eth0
-rw------- 1 root root 763 Jan 14 09:58 mynet-cnitool-49346948b0d506e05f2d-eth0
-rw------- 1 root root 763 Jan 14 10:15 mynet-cnitool-c11ae72283507a6e6b3c-eth0
# cat mynet-cnitool-49346948b0d506e05f2d-eth0 | jq .
{
"kind": "cniCacheV1",
"containerId": "cnitool-49346948b0d506e05f2d",
"config": "eyJjbmlWZXJzaW9uIjoiMC40LjAiLCJuYW1lIjoibXluZXQiLCJwbHVnaW5zIjpbeyJicmlkZ2UiOiJteWJyaWRnZSIsImNuaVZlcnNpb24iOiIwLjQuMCIsImlwYW0iOnsic3VibmV0IjoiMTkyLjE2OC4xMDAuMC8yNCIsInR5cGUiOiJob3N0LWxvY2FsIn0sImlzRGVmYXVsdEdhdGV3YXkiOnRydWUsIm5hbWUiOiJteW5ldCIsInR5cGUiOiJicmlkZ2UifV19",
"ifName": "eth0",
"networkName": "mynet",
"result": {
"cniVersion": "0.4.0",
"dns": {},
"interfaces": [
{
"mac": "3e:af:39:a3:b4:93",
"name": "mybridge"
},
{
"mac": "96:8b:02:29:7a:84",
"name": "veth0820d945"
},
{
"mac": "e2:ab:88:4c:67:2d",
"name": "eth0",
"sandbox": "/var/run/netns/testing1"
}
],
"ips": [
{
"address": "192.168.100.2/24",
"gateway": "192.168.100.1",
"interface": 2,
"version": "4"
}
],
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "192.168.100.1"
}
]
}
}
# cat mynet-cnitool-256083c5997e421f082a-eth0 |jq .
{
"kind": "cniCacheV1",
"containerId": "cnitool-256083c5997e421f082a",
"config": "eyJjbmlWZXJzaW9uIjoiMC40LjAiLCJuYW1lIjoibXluZXQiLCJwbHVnaW5zIjpbeyJicmlkZ2UiOiJteWJyaWRnZSIsImNuaVZlcnNpb24iOiIwLjQuMCIsImlwYW0iOnsic3VibmV0IjoiMTkyLjE2OC4xMDAuMC8yNCIsInR5cGUiOiJob3N0LWxvY2FsIn0sImlzRGVmYXVsdEdhdGV3YXkiOnRydWUsIm5hbWUiOiJteW5ldCIsInR5cGUiOiJicmlkZ2UifV19",
"ifName": "eth0",
"networkName": "mynet",
"result": {
"cniVersion": "0.4.0",
"dns": {},
"interfaces": [
{
"mac": "3e:af:39:a3:b4:93",
"name": "mybridge"
},
{
"mac": "76:59:67:9d:1a:14",
"name": "vethdc29b15e"
},
{
"mac": "e2:55:2e:09:ad:75",
"name": "eth0",
"sandbox": "/var/run/netns/testing2"
}
],
"ips": [
{
"address": "192.168.100.3/24",
"gateway": "192.168.100.1",
"interface": 2,
"version": "4"
}
],
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "192.168.100.1"
}
]
}
}
# cat mynet-cnitool-c11ae72283507a6e6b3c-eth0 | jq .
{
"kind": "cniCacheV1",
"containerId": "cnitool-c11ae72283507a6e6b3c",
"config": "eyJjbmlWZXJzaW9uIjoiMC40LjAiLCJuYW1lIjoibXluZXQiLCJwbHVnaW5zIjpbeyJicmlkZ2UiOiJteWJyaWRnZSIsImNuaVZlcnNpb24iOiIwLjQuMCIsImlwYW0iOnsic3VibmV0IjoiMTkyLjE2OC4xMDAuMC8yNCIsInR5cGUiOiJob3N0LWxvY2FsIn0sImlzRGVmYXVsdEdhdGV3YXkiOnRydWUsIm5hbWUiOiJteW5ldCIsInR5cGUiOiJicmlkZ2UifV19",
"ifName": "eth0",
"networkName": "mynet",
"result": {
"cniVersion": "0.4.0",
"dns": {},
"interfaces": [
{
"mac": "3e:af:39:a3:b4:93",
"name": "mybridge"
},
{
"mac": "16:f9:fd:71:5e:a0",
"name": "vethc3a9e0b8"
},
{
"mac": "6e:f8:3d:da:f0:bb",
"name": "eth0",
"sandbox": "/var/run/netns/testing3"
}
],
"ips": [
{
"address": "192.168.100.4/24",
"gateway": "192.168.100.1",
"interface": 2,
"version": "4"
}
],
"routes": [
{
"dst": "0.0.0.0/0",
"gw": "192.168.100.1"
}
]
}
}
これらの情報と、CNI Pluginのソースコードでの挙動がマッチングできれば、将来、CNI Pluginの独自開発に役立つはず。
■ Namespace環境のクリーンナップ
最後に、環境をキレイに戻しておきましょう。
# CNI_PATH=/root/plugins/bin cnitool del mynet /var/run/netns/testing1
# CNI_PATH=/root/plugins/bin cnitool del mynet /var/run/netns/testing2
# CNI_PATH=/root/plugins/bin cnitool del mynet /var/run/netns/testing3
# ip link set mybridge down
# brctl delbr mybridge
# ip netns del testing1
# ip netns del testing2
# ip netns del testing3
以上です。。。
■ (追記)IPv4/IPv6 DualStackのIPAM動作を確認する
追加確認として、"host-local IP address management plugin"を参考に、IPv4/IPv6 DualStackのIPAM動作を確認してみます
# CNI_COMMAND=ADD CNI_CONTAINERID=example CNI_NETNS=/dev/null CNI_IFNAME=dummy0 CNI_PATH=. /root/plugins/bin/host-local << EOS
> {
> "cniVersion": "0.3.1",
> "name": "examplenet",
> "ipam": {
> "type": "host-local",
> "ranges": [
> [
> {
> "subnet": "203.0.113.0/24"
> }
> ],
> [
> {
> "subnet": "2001:db8:1::/64"
> }
> ]
> ],
> "dataDir": "/tmp/cni-example"
> }
> }
> EOS
{
"cniVersion": "0.3.1",
"ips": [
{
"version": "4",
"address": "203.0.113.2/24",
"gateway": "203.0.113.1"
},
{
"version": "6",
"address": "2001:db8:1::2/64",
"gateway": "2001:db8:1::1"
}
],
"dns": {}
}
いい感じに、動作できている。