🙆

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-01my-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