Dockerのネットワーク構成

Dockerのネットワーク基本構成

最初にイメージ図をみてみます。この内容をコマンドで確認していきます。

DockerホストからIPアドレスを確認してみます。

ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:e8:5c:ea brd ff:ff:ff:ff:ff:ff
    inet 192.168.47.15/24 brd 192.168.47.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fee8:5cea/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 02:42:75:5d:f2:f0 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:75ff:fe5d:f2f0/64 scope link
       valid_lft forever preferred_lft forever

コンテナが起動していない状態でBridgeを確認します。

BridgのDocker0が作成してありますが、interfaceは接続されていません。

brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242755df2f0	no

brctlコマンド

bidgeを確認するためには以下のツールをインストールしてください。

yum -y install bridge-utils

Dockerのネットワークを確認します。

bridge:コンテナをbridgeで接続されます。通常起動したコンテナはこのネットワークに接続します。 host:Dockerホストと同じネットワークに接続します。IPアドレスはDockerホストと同じになります。 none:いわゆる隔離LAN。コンテナはルーブバックインターフェースしか取り付けられません。

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f183201ca025        bridge              bridge              local
fe5db9777b4e        host                host                local
8a96a1a8f4cf        none                null                local

実際にポートを指定してコンテナを起動します。

docker run -d --name ubuntu -p 8000:80 ubuntu init
87e85b88d3beb5e98ac41a144380ac0d592889c376fc28bf4e2acbb64885ce16

コンテナ起動状態でIPアドレスを確認します。 新たに仮想インターフェース(veth)が接続されています。 さらに見るとこのvethはdocker0と接続しています。

ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:e8:5c:ea brd ff:ff:ff:ff:ff:ff
    inet 192.168.47.15/24 brd 192.168.47.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fee8:5cea/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:75:5d:f2:f0 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:75ff:fe5d:f2f0/64 scope link
       valid_lft forever preferred_lft forever
158: veth34b8416@if157: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
    link/ether d6:34:ed:e6:fe:81 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::d434:edff:fee6:fe81/64 scope link
       valid_lft forever preferred_lft forever

コンテナ起動後にBridgeを確認してみます。 docker0にvethが接続されています。

brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242755df2f0	no		veth34b8416

コンテナ内のネットワーク情報を確認します。 IPアドレス「172.17.0.2」が割り当てられています。 このIPアドレスはコンテナ名前空間で割り当てられているため、Dockerホストの「ip a」コマンドでは出力されません。

docker inspect ubuntu
...
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "f183201ca025e3225544932a511b7f677f10a7c05debfb6b423470a6a25faca1",
                    "EndpointID": "39004c844255d5eed0cc153335224ff8841d5cbea28e6a73e0b1fc814fffc939",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
...

コンテナが外部ネットワークと通信できているのはiptablesのおかげです。 iptablesによってNAT・IPマスカレードをしているため、外部との通信やポートでのコンテナ通信が実現しています。

iptables -L -t nat
...
Chain POSTROUTING (policy ACCEPT)
target                    prot               opt source               destination
MASQUERADE                all                --  172.17.0.0/16        anywhere
POSTROUTING_direct        all                --  anywhere             anywhere
POSTROUTING_ZONES_SOURCE  all                --  anywhere             anywhere
POSTROUTING_ZONES         all                --  anywhere             anywhere
MASQUERADE                tcp                --  172.17.0.2           172.17.0.2           tcp dpt:http

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
DNAT       tcp  --  anywhere             anywhere             tcp dpt:irdmi to:172.17.0.2:80
...

振り返りにもう一度イメージをみてみます。Dockerのネットワーク構成は難しいようで、あまり複雑ではありません。 IPマスカレードやNATの知識があれば十分理解できそうです。

Docker Composeを使った場合

まずはDocker ComposeでWordPress-DB構成のymlファイルを準備します。

mkdir /opt/wordpress
cd /opt/
vi docker-compose.yml
version: '3'
# servicesでdb,wordpressというコンテナを作成する
services:
   db:
     # Dockerイメージに使用するイメージを設定
     image: mysql:5.7
     # ローカルにデータを保持するディレクトリパスを指定(データの永続化)
     volumes:
       - db_data:/var/lib/mysql
     # restartポリシーをalwaysに設定
     restart: always
     # 環境変数を指定します。dbの設定ファイルに任意で設定する必要がある情報です。
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     # 起動順序を設定、この場合dbの起動後にwordpressを起動します。
     depends_on:
       - db
     image: wordpress:latest
     # wordpressのデータが入っているディレクトリを永続化します。
     # ホストのディレクトリ:コンテナ内のディレクトリ
     volumes:
       - /opt/wordpress/html:/var/www/html/

     # ポートの接続、8000ポートで受け付けてwordpressコンテナに80ポートへ通信させます。
     # 今回は80ポートで接続できるようにしました。
     ports:
       - "80:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress

volumes:
    db_data:

docker-composeでworpdressを立ち上げます。 すると「wordpress_default」のネットワークが作成されるのがわかります。

docker-compose up -d
Creating network "wordpress_default" with the default driver
Creating wordpress_db_1 ...
Creating wordpress_db_1 ... done
Creating wordpress_wordpress_1 ...
Creating wordpress_wordpress_1 ... done

ネットワークを確認するとbridgeのネットワークにwordpress_defaultがあります。

docker network list
NETWORK ID          NAME                DRIVER              SCOPE
f183201ca025        bridge              bridge              local
fe5db9777b4e        host                host                local
8a96a1a8f4cf        none                null                local
8af5af17aacb        wordpress_default   bridge              local

Dockerホストからインターフェースを確認します。 新たにBridge「br-8af5af17aacb」とvethペアが2つ作成されています。

ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:e8:5c:ea brd ff:ff:ff:ff:ff:ff
    inet 192.168.47.15/24 brd 192.168.47.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fee8:5cea/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:75:5d:f2:f0 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:75ff:fe5d:f2f0/64 scope link
       valid_lft forever preferred_lft forever
162: vethb688c76@if161: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
    link/ether 72:88:17:8c:ec:2b brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::7088:17ff:fe8c:ec2b/64 scope link
       valid_lft forever preferred_lft forever
163: br-8af5af17aacb: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:1c:85:70:79 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 scope global br-8af5af17aacb
       valid_lft forever preferred_lft forever
    inet6 fe80::42:1cff:fe85:7079/64 scope link
       valid_lft forever preferred_lft forever
165: veth90e85b2@if164: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-8af5af17aacb state UP
    link/ether 42:ff:21:22:2a:fc brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::40ff:21ff:fe22:2afc/64 scope link
       valid_lft forever preferred_lft forever
167: veth49f7070@if166: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-8af5af17aacb state UP
    link/ether a2:65:30:8c:74:77 brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::a065:30ff:fe8c:7477/64 scope link
       valid_lft forever preferred_lft forever

新たに作成されたbridgeにvethが2つ接続されています。

brctl show
bridge name	 bridge id		STP enabled	interfaces
br-8af5af17aacb  8000.02421c857079	no		veth49f7070
							veth90e85b2
docker0		 8000.0242755df2f0	no		vethb688c76

wordpress_defaultのネットワークを確認します。 default_gatewayやコンテナのIPアドレスが確認できます。

docker network inspect <NAME>
docker network inspect wordpress_default
[
    {
        "Name": "wordpress_default",
        "Id": "8af5af17aacb8f069d12c003c49423b8c3b8d748206f6a94f6710fc934a6cd78",
        "Created": "2017-11-19T01:01:19.540971083+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "2a5b1125e553980232689f28f247317581f6c4da6656321fc8fe67e07fd62b5c": {
                "Name": "wordpress_wordpress_1",
                "EndpointID": "1d8052f748024e38cab0338f851458a5519689080d6a4115a6a75ae5b96d2ae8",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "d64fb12e69638f6cf272f3f1163193c7676f03c634bf432639cf3ffc0060dfd8": {
                "Name": "wordpress_db_1",
                "EndpointID": "1dd1188fc2c84794c1947b6c84a865955754537c7425310c48cb070bc6942a0d",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "wordpress"
        }
    }
]

iptables設定は以下のようになります。

iptables -L -t nat
...
Chain POSTROUTING (policy ACCEPT)
target                    prot opt source               destination
MASQUERADE                all  --  172.18.0.0/16        anywhere
MASQUERADE                all  --  172.17.0.0/16        anywhere
POSTROUTING_direct        all  --  anywhere             anywhere
POSTROUTING_ZONES_SOURCE  all  --  anywhere             anywhere
POSTROUTING_ZONES         all  --  anywhere             anywhere
MASQUERADE                tcp  --  172.17.0.2           172.17.0.2           tcp dpt:http
MASQUERADE                tcp  --  172.18.0.3           172.18.0.3           tcp dpt:http

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere
DNAT       tcp  --  anywhere             anywhere             tcp dpt:irdmi to:172.17.0.2:80
DNAT       tcp  --  anywhere             anywhere             tcp dpt:http to:172.18.0.3:80
...

イメージ図

Dockerのネットワークは難しくない

dockerでは内部で動いているネットワークが非常に見えづらいので難しく感じることもありますが、基本はiptablesによるNAT・IPマスカレードの制御です。 これを理解しておけばあとは応用するだけです。

iptablesの操作に注意

dockerとは関係なくiptablesを変更することもあると思います。変更後にiptablesを再起動するとDockerの設定が消えますので、ipatalesを変更した場合はdockerプロセスも再起動しましょう。