Opensourcetechブログ

OpensourcetechによるLinux・オープンソース・IT技術などに関するブログです。

Dockerコンテナのネットワークについて

 

 

こんにちは、LinuCエバンジェリストこと、鯨井貴博@opensourcetechです。

 

今回は、Dockerコンテナのネットワークについて調べてみました。

Dockerの導入については、こちらを見てください。

docker 〜Dockerfile を使用した、コンテナの作成・起動〜 - Opensourcetechブログ

 

 

 Dockerコンテナですが、以下の構成にあるバックエンドサーバ nginx 3台を使っています。

f:id:opensourcetech:20181122154141p:plain

※以下の記事で作った構成です。

NGINX Plusによるリバースプロキシ構築 - Opensourcetechブログ



まず、起動しているコンテナの情報を確認します。

[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
911f5d0e2499 nginx "nginx -g 'daemon of…" 43 hours ago Up 2 hours 0.0.0.0:8083->80/tcp laughing_liskov ・・・コンテナ1
0e9d799bd46a nginx "nginx -g 'daemon of…" 43 hours ago Up 2 hours 0.0.0.0:8082->80/tcp practical_boyd・・・コンテナ2
d39f6d85d65f nginx "nginx -g 'daemon of…" 43 hours ago Up 2 hours 0.0.0.0:8081->80/tcp pensive_cohen・・・コンテナ3

 

では、この状態でコンテナのネットワークはどうなっているか、

ip addr showで確認します。

[root@localhost ~]# ip addr show
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:96:f6:c0 brd ff:ff:ff:ff:ff:ff
inet 192.168.13.3/24 brd 192.168.13.255 scope global noprefixroute dynamic enp0s3
valid_lft 22215sec preferred_lft 22215sec
inet6 fe80::e830:c2da:441:a2d7/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::e77f:5380:24e5:f200/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::bba:f6af:15f8:fdcb/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
noqueue state UP group default
link/ether 02:42:ac:e9:8e:65 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fee9:8e65/64 scope link
valid_lft forever preferred_lft forever
5: veth6e13a71@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 2a:74:10:58:17:3d brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::2874:10ff:fe58:173d/64 scope link
valid_lft forever preferred_lft forever
7: veth3e496ad@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 0e:a2:b7:51:16:f0 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::ca2:b7ff:fe51:16f0/64 scope link
valid_lft forever preferred_lft forever
9: veth4f2f0d6@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 22:fc:05:1f:75:32 brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet6 fe80::20fc:5ff:fe1f:7532/64 scope link
valid_lft forever preferred_lft forever

 

上記の中の、「3: docker0」がDocker用に作られたインターフェイス

「vethXXXXXXXX`XXX」とあるのが各コンテナに使用されるインターフェイスとなります。

図にすると、以下のようになります。

f:id:opensourcetech:20181122172909p:plain

 

インターフェイスの意味は、以下の通りです。

docker0:Dockerコンテナ全体で使用される中心的なインターフェイス

veth:各コンテナのインターフェイスとペアとなるインターフェイス

 

 

そして、上記インターフェイスの関係を作成する為に必要な情報の確認方法を見ていきます。

 

 

 情報の確認には、docker inspectコマンドを使用します。

docker inspect | Docker Documentation

 

各コンテナ インターフェイスIPアドレス確認

[root@localhost ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' d39f6d85d65f
172.17.0.4
[root@localhost ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 0e9d799bd46a
172.17.0.3
[root@localhost ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 911f5d0e2499
172.17.0.2

 

各コンテナ インターフェイスMACアドレス確認

[root@localhost ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' d39f6d85d65f
02:42:ac:11:00:04
[root@localhost ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' 0e9d799bd46a
02:42:ac:11:00:03
[root@localhost ~]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' 911f5d0e2499
02:42:ac:11:00:02

 

 各コンテナとHostPCのポートバインド情報確認

以下だと、コンテナのTCP80番ポートと、HostPCの8081 / 8082 / 8083がバインとされていることが確認できます。

[root@localhost ~]# docker inspect --format='{{(index (index .NetworkSettings.Ports "80/tcp") 0).HostPort}}' d39f6d85d65f
8081
[root@localhost ~]# docker inspect --format='{{(index (index .NetworkSettings.Ports "80/tcp") 0).HostPort}}' 0e9d799bd46a
8082
[root@localhost ~]# docker inspect --format='{{(index (index .NetworkSettings.Ports "80/tcp") 0).HostPort}}' 911f5d0e2499
8083

 

 同様のものは、以下でも確認できます。

[root@localhost ~]# docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' d39f6d85d65f
80/tcp -> 8081
[root@localhost ~]# docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' 0e9d799bd46a
80/tcp -> 8082
[root@localhost ~]# docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' 911f5d0e2499
80/tcp -> 8083

 

brctl(bridge-utilsパッケージに含まれる)で、docker0とvethの関連が確認できます。

[root@localhost ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242ace98e65 no veth3e496ad
                                                      veth4f2f0d6
                                                      vethc50278d

 

 

この操作で、各コンテナのネットワークに関する情報は分かりましたが、

vethと各コンテナ インターフェイスの関連性(どのvethが、どのコンテナに対応するかどうか)については確認ができません

 

 

ここで重要なのが、Dockerコンテナが動作している裏には、

Linux Kernelのシステムリソース分離機能である cgroups(namespaces:名前空間 と呼んでもいいかもしれませんが)を知ること。

https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt

Man page of NAMESPACES

 

以下のDocker overviewにも書いてあります。

Docker overview | Docker Documentation

 

 

そして、Dockerコンテナで使われている名前空間のうち、ネットワーク名前空間を見ていくと「vethと各コンテナインターフェイスの関連性」が確認できます。

 

方法としては、以下GitHubにある「docker-netns.sh」というスクリプトを使用しました。

GitHub - pujoheadsoft/docker-netns

 

gitが必要なので、入っていない場合は「yum install git」などでインストールします。

[root@localhost ~]# git clone https://github.com/pujoheadsoft/docker-netns.git
Cloning into 'docker-netns'...
remote: Enumerating objects: 12, done.
remote: Total 12 (delta 0), reused 0 (delta 0), pack-reused 12
Unpacking objects: 100% (12/12), done.
[root@localhost ~]# ls
anaconda-ks.cfg docker-netns lldptool.man
[root@localhost ~]# cd docker-netns/
[root@localhost docker-netns]# ls -l
合計 8
-rw-r--r--. 1 root root 280 11月 20 20:55 README.md
-rw-r--r--. 1 root root 3972 11月 20 20:55 docker-netns.sh
[root@localhost docker-netns]# chmod +x docker-netns.sh
[root@localhost docker-netns]# ls -l
合計 8
-rw-r--r--. 1 root root 280 11月 20 20:55 README.md
-rwxr-xr-x. 1 root root 3972 11月 20 20:55 docker-netns.sh
[root@localhost docker-netns]# ./docker-netns.sh visible
container's network namespace to visible, you can show container's nemespace by [ip netns] command.
[root@localhost docker-netns]# ip netns
d39f6d85d65f (id: 2)
0e9d799bd46a (id: 1)
911f5d0e2499 (id: 0)
[root@localhost docker-netns]# ./docker-netns.sh showveth ・・・これで各コンテナが使用しているvethの確認ができます!
VETH CONTAINER ID NAMES
vethc50278d 911f5d0e2499 /laughing_liskov
veth3e496ad 0e9d799bd46a /practical_boyd
veth4f2f0d6 d39f6d85d65f /pensive_cohen
[root@localhost docker-netns]# ./docker-netns.sh showip
CONTAINER ID IP NAMES
911f5d0e2499 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 /laughing_liskov
0e9d799bd46a inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0 /practical_boyd
d39f6d85d65f inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0 /pensive_cohen

 

上記のスクリプトの中で行われていることは、

以下のソースコードを見れば分かりますが、

/proc/コンテナプロセスのPID/ns/net を/var/run/netns/コンテナのID としてシンボリックリンクを設定し 通常では見れない ネットワーク名前空間の情報を確認しています。

docker-netns/docker-netns.sh at master · pujoheadsoft/docker-netns · GitHub

f:id:opensourcetech:20181122180836p:plain

 

 

 

ん〜、Dockerコンテナ ネットワーク 、Linux kernel(cgoupsやら名前空間)んどいろいろ勉強になりますね。

 

 

 

 

www.slideshare.net

github.com

www.facebook.com

twitter.com

www.instagram.com

 

 

にほんブログ村 IT技術ブログ Linuxへ
Linux

にほんブログ村 IT技術ブログ オープンソースへ
オープンソース

 

 

Opensourcetech by Takahiro Kujirai