dockerの仮想ネットワークとhostのネットワークの接続を確認
Linuxのnamespaceという機能
Linuxのnamespace(名前空間)とは、「プロセスから見えるリソースの範囲(スコープ)を分離する仕組み」です。 1つのホスト環境で論理的に複数の環境(namespace)として分離してリソースを管理することできます。主にコンテナ技術(例:Docker)などで使われ、1つのLinuxカーネル上で独立した仮想的な環境を作るために用いられます。このnamespace機能があるからこそ、1つのホスト環境で複数のコンテナが独立した環境として動くことできます。
Namespace | 分離されるリソース | 説明 |
---|---|---|
mnt |
マウントポイント(ファイルシステム) | 各プロセスが見えるファイルシステムを独立させる(例:別の / ルートを持つ) |
pid |
プロセスID | 他の namespace のプロセスが見えなくなる(init プロセスのように見える) |
net |
ネットワーク(インターフェース、ルーティングなど) | 独自のネットワークインターフェースや IP 設定が可能 |
ipc |
IPC リソース(共有メモリ、メッセージキューなど) | 他のプロセスと共有されない IPC を使用可能 |
uts |
ホスト名・ドメイン名 | ホスト名を独立させられる(例:コンテナごとに別ホスト名) |
user |
ユーザーとグループ ID | コンテナ内では root でも、ホストでは非特権ユーザーとして扱える |
cgroup |
リソース制限(CPU、メモリなど) | namespace と併用してリソース制御が可能(cgroup 自体は別機能) |
namespaceを確認してみる
Linuxではデフォルトでは、単一のnamespaceを利用しています。
例えば、netのnamespace(4026531992)は103個のプロセスが利用しています。
sh-4.2$ sudo lsns
NS TYPE NPROCS PID USER COMMAND
4026531992 net 103 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531835 cgroup 106 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531836 pid 103 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531837 user 106 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531838 uts 103 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531839 ipc 103 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531840 mnt 101 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531860 mnt 1 23 root kdevtmpfs
4026532168 mnt 1 1833 chrony /usr/sbin/chronyd -F 2
ssmで接続中のプロセスでnamespaceを確認してみます。
sudo lsns
で出力されたnamespaceと同じnamespaceを利用していることが確認できました。
sh-4.2$ ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:22 net -> net:[4026531992]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:22 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:22 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:22 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:22 pid -> pid:[4026531836]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:24 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:24 time -> time:[4026531834]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:24 time_for_children -> time:[4026531834]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:22 user -> user:[4026531837]
lrwxrwxrwx 1 ssm-user ssm-user 0 Jun 7 07:22 uts -> uts:[4026531838]
dockerコンテナが独自のnamespaceを持つことを確認
dockerコンテナを起動
docker run -d --name c1 alpine sleep 3000
docker run -d --name c2 alpine sleep 3000
docker run -d --name c3 alpine sleep 3000
namespace一覧を確認
PID:10035,10116,10199にて新しいnamespaceが作成されています。
sh-4.2$ sudo lsns
NS TYPE NPROCS PID USER COMMAND
4026531835 cgroup 108 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531836 pid 105 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531837 user 108 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531838 uts 105 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531839 ipc 105 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531840 mnt 103 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531860 mnt 1 23 root kdevtmpfs
4026531992 net 105 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026532168 mnt 1 1833 chrony /usr/sbin/chronyd -F 2
4026532193 mnt 1 10035 root sleep 3000
4026532194 uts 1 10035 root sleep 3000
4026532195 ipc 1 10035 root sleep 3000
4026532196 pid 1 10035 root sleep 3000
4026532198 net 1 10035 root sleep 3000
4026532268 mnt 1 10116 root sleep 3000
4026532269 uts 1 10116 root sleep 3000
4026532270 ipc 1 10116 root sleep 3000
4026532271 pid 1 10116 root sleep 3000
4026532273 net 1 10116 root sleep 3000
4026532343 mnt 1 10199 root sleep 3000
4026532344 uts 1 10199 root sleep 3000
4026532345 ipc 1 10199 root sleep 3000
4026532346 pid 1 10199 root sleep 3000
4026532348 net 1 10199 root sleep 3000
新しくできたnamespaceを確認
PID10035のnamespaceを確認します。
新しく作成されたnamespaceと既存のhost環境のnamespaceを利用しているものと併用していることが分かります。
sh-4.2$ sudo ls -l /proc/10035/ns
total 0
lrwxrwxrwx 1 root root 0 Jun 7 07:35 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jun 7 07:35 ipc -> ipc:[4026532195]
lrwxrwxrwx 1 root root 0 Jun 7 07:35 mnt -> mnt:[4026532193]
lrwxrwxrwx 1 root root 0 Jun 7 07:35 net -> net:[4026532198]
lrwxrwxrwx 1 root root 0 Jun 7 07:35 pid -> pid:[4026532196]
lrwxrwxrwx 1 root root 0 Jun 7 07:38 pid_for_children -> pid:[4026532196]
lrwxrwxrwx 1 root root 0 Jun 7 07:38 time -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Jun 7 07:38 time_for_children -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Jun 7 07:35 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jun 7 07:35 uts -> uts:[4026532194]
下記が、10035で新しく作成されたnamespaceです。
4026532193 mnt 1 10035 root sleep 3000
4026532194 uts 1 10035 root sleep 3000
4026532195 ipc 1 10035 root sleep 3000
4026532196 pid 1 10035 root sleep 3000
4026532198 net 1 10035 root sleep 3000
仮想ネットワーク
このnamespaceという仮想環境をネットワークを軸に掘り下げていきます。
ホスト環境のネットワークインターフェースを確認
sh-4.2$ sudo ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 06:e1:cd:02:9c:0b brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:4d:b7:c2:a3 brd ff:ff:ff:ff:ff:ff
23: vethadb83fd@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether be:18:f7:aa:3d:76 brd ff:ff:ff:ff:ff:ff link-netnsid 0
25: veth208d5dd@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether ca:6b:9e:11:0b:2f brd ff:ff:ff:ff:ff:ff link-netnsid 1
27: veth2f9589c@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether 72:32:fa:76:27:a5 brd ff:ff:ff:ff:ff:ff link-netnsid 2
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
localhost用
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 06:e1:cd:02:9c:0b brd ff:ff:ff:ff:ff:ff
eth0 通常の物理ネットワークカード(NIC)、外部との通信時に利用される
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:4d:b7:c2:a3 brd ff:ff:ff:ff:ff:ff
Docker が自動で作る「仮想ブリッジ」。コンテナとの接続ハブの役割をする。
23: vethadb83fd@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether be:18:f7:aa:3d:76 brd ff:ff:ff:ff:ff:ff link-netnsid 0
25: veth208d5dd@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether ca:6b:9e:11:0b:2f brd ff:ff:ff:ff:ff:ff link-netnsid 1
27: veth2f9589c@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether 72:32:fa:76:27:a5 brd ff:ff:ff:ff:ff:ff link-netnsid 2
仮想 Ethernet ペア。コンテナとの接続の役割を担う。veth が docker0 ブリッジに接続される。
コンテナとホストとのネットワーク接続を確認
下記のような接続関係になっているようです。
[コンテナ内 eth0]
│
[vethXXX@ifYY] ← ホスト側のNIC(名前付き)
│
[docker0 ブリッジ] ← 仮想スイッチ
│
[eth0] ← ホストのNIC、外部への出入口
[コンテナ内 eth0] -- [vethXXX@ifYY] との接続
コンテナに入ってeth0の番号を確認
sh-4.2$ sudo docker exec -it 19d298124e21 sh
/ #
/ # cat /sys/class/net/eth0/ifindex
26
link/ether ca:6b:9e:11:0b:2f brd ff:ff:ff:ff:ff:ff link-netnsid 1
27: veth2f9589c@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
@if26
なので、veth2f9589c@if26 と接続しています。
[vethXXX@ifYY] --- [docker0 ブリッジ] との接続
docker0と3つのvethが接続されていることが分かります。
sh-4.2$ brctl show docker0
bridge name bridge id STP enabled interfaces
docker0 8000.02424db7c2a3 no veth208d5dd
veth2f9589c
vethadb83fd
dockerで新規ネットワークを作成した場合の仮想化と接続
ネットワーク作成 & 新ネットワークでコンテナ起動
sh-4.2$ sudo docker network create my-net
sh-4.2$ sudo docker run -d --name c4 --network my-net alpine sleep 3000
結果としては
- namespaceが追加
- 新しいネットワークインターフェースが追加(br-a3b53aa990d8、veth72ba4ad)
sh-4.2$ sudo lsns
NS TYPE NPROCS PID USER COMMAND
4026531835 cgroup 106 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531836 pid 102 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531837 user 106 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531838 uts 102 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531839 ipc 102 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531840 mnt 100 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026531860 mnt 1 23 root kdevtmpfs
4026531992 net 102 1 root /usr/lib/systemd/systemd --system --deserialize 33
4026532168 mnt 1 1833 chrony /usr/sbin/chronyd -F 2
4026532193 mnt 1 10035 root sleep 3000
4026532194 uts 1 10035 root sleep 3000
4026532195 ipc 1 10035 root sleep 3000
4026532196 pid 1 10035 root sleep 3000
4026532198 net 1 10035 root sleep 3000
4026532268 mnt 1 10116 root sleep 3000
4026532269 uts 1 10116 root sleep 3000
4026532270 ipc 1 10116 root sleep 3000
4026532271 pid 1 10116 root sleep 3000
4026532273 net 1 10116 root sleep 3000
4026532343 mnt 1 10199 root sleep 3000
4026532344 uts 1 10199 root sleep 3000
4026532345 ipc 1 10199 root sleep 3000
4026532346 pid 1 10199 root sleep 3000
4026532348 net 1 10199 root sleep 3000
4026532419 mnt 1 10697 root sleep 3000
4026532420 uts 1 10697 root sleep 3000
4026532421 ipc 1 10697 root sleep 3000
4026532422 pid 1 10697 root sleep 3000
4026532424 net 1 10697 root sleep 3000
sh-4.2$ sudo ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 06:e1:cd:02:9c:0b brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:4d:b7:c2:a3 brd ff:ff:ff:ff:ff:ff
23: vethadb83fd@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether be:18:f7:aa:3d:76 brd ff:ff:ff:ff:ff:ff link-netnsid 0
25: veth208d5dd@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether ca:6b:9e:11:0b:2f brd ff:ff:ff:ff:ff:ff link-netnsid 1
27: veth2f9589c@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether 72:32:fa:76:27:a5 brd ff:ff:ff:ff:ff:ff link-netnsid 2
28: br-a3b53aa990d8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:11:e8:4c:18 brd ff:ff:ff:ff:ff:ff
30: veth72ba4ad@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-a3b53aa990d8 state UP mode DEFAULT group default
link/ether 82:4e:63:4c:39:fc brd ff:ff:ff:ff:ff:ff link-netnsid 3
sh-4.2$ brctl show
bridge name bridge id STP enabled interfaces
br-a3b53aa990d8 8000.024211e84c18 no veth72ba4ad
docker0 8000.02424db7c2a3 no veth208d5dd
veth2f9589c
vethadb83fd
違う仮想ネットワークに通信ができるか?
出来ないです。
my-network-01
とmy-network-02
の2つのネットワークを作成し、コンテナ同士で疎通できるかを確認します。
ネットワーク別にコンテナを作成
sudo docker run -d --name c4-01 --network my-net-01 alpine sleep 3000
sudo docker run -d --name c5-01 --network my-net-01 alpine sleep 3000
sudo docker run -d --name c6-02 --network my-net-02 alpine sleep 3000
sudo docker run -d --name c7-02 --network my-net-02 alpine sleep 3000
疎通確認
- 同じネットワーク内であれば疎通OK
- 違うネットワークだと疎通NG
成功
sudo docker exec -it c4-01 ping c5-01
PING c5-01 (172.20.0.3): 56 data bytes
64 bytes from 172.20.0.3: seq=0 ttl=127 time=0.113 ms
64 bytes from 172.20.0.3: seq=1 ttl=127 time=0.072 ms
成功
sudo docker exec -it c6-02 ping c7-02
PING c7-02 (172.21.0.3): 56 data bytes
64 bytes from 172.21.0.3: seq=0 ttl=127 time=0.104 ms
64 bytes from 172.21.0.3: seq=1 ttl=127 time=0.083 ms
失敗
sh-4.2$ sudo docker exec -it c6-02 ping c5-01
ping: bad address 'c5-01'
補足
defultのbridgeネットワークでは、コンテナ名で名前解決できません。
カスタムで作成したネットワークでは、コンテナ名で名前解決できます。
Discussion