Docker コンテナ・ネットワークの理解

ウェブ・アプリケーションの構築は、安全についての考慮が必要であり、そのために Docker ネットワーク機能を使います。ネットワークとは、定義上、コンテナのために完全な分離(isolation)を提供するものです。そして、アプリケーションの実行にあたり、ネットワーク管理は重要であることを意味します。Docker コンテナ・ネットワークは、これらを管理するものです。

このセクションでは、Docker Engine ドライバ固有の標準ネットワーク機能について、その概要を扱います。ここでは標準のネットワーク・タイプについてと、どのようにして自分自身でユーザ定義ネットワークを使うのかを説明します。また、単一ホストまたはクラスタ上をまたがるホストにネットワークを作成するために必要なリソースについても説明します。

デフォルト・ネットワーク

Docker をインストールすると、自動的に3つのネットワークを作成します。ネットワーク一覧を表示するには docker network ls コマンドを使います。

$ docker network ls
NETWORK ID          NAME                DRIVER
7fca4eb8c647        bridge              bridge
9f904ee27bf5        none                null
cf03ee007fb4        host                host

これまで、3つのネットワークが Docker の一部として実装されています。コンテナを実行するネットワークを指定したいときは、 -net フラグを使うことができました。これらの3つのネットワークは、まだ今も利用可能です。

Docker をインストールした全ての環境には、 docker0 と表示される bridge ネットワークが現れます。オプションで docker run --net=<ネットワーク名> を指定しない限り、Docker デーモンはデフォルトでこのネットワークにコンテナを接続します。ホスト上で ifconfig コマンドを使うことで、ホストネットワーク上のスタックの一部として、このブリッジを見ることができます。

ubuntu@ip-172-31-36-118:~$ ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:47:bc:3a:eb
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:47ff:febc:3aeb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:17 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1100 (1.1 KB)  TX bytes:648 (648.0 B)

ネットワーク層に何も追加しない none ネットワークをコンテナを追加したとします。そのコンテナはネットワーク・インターフェースが欠如しています。コンテナに接続(アタッチ)すると、次のようにスタックが表示されます。

ubuntu@ip-172-31-36-118:~$ docker attach nonenetcontainer

/ # cat /etc/hosts
127.0.0.1    localhost
::1  localhost ip6-localhost ip6-loopback
fe00::0      ip6-localnet
ff00::0      ip6-mcastprefix
ff02::1      ip6-allnodes
ff02::2      ip6-allrouters
/ # ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ #

注釈

コンテナから離れても実行したままにするには、 CTRL-p CTRL-q を押します。

ホスト・ネットワーク・スタック上のコンテナに host ネットワークを追加したとします。コンテナ内のネットワーク設定が、ホスト上と同じであるように見えるでしょう。

bridge ネットワーク使用時をのぞき、これらデフォルト・ネットワークと実際に通信する必要はありません。このように一覧を表示したり調べたりしても、これらを削除できません。これらは Docker のインストールに必要とされているためです。しかしながら、自分自身でユーザ定義ネットワークを追加することができ、また、必要が無いものを削除できます。自分自身のネットワークについて学ぶ前に、デフォルトのネットワークについて少しだけ見ておきましょう。

デフォルトのブリッジ・ネットワーク詳細

Docker ホスト上の全てのデフォルト・ネットワーク・ブリッジを表示するには、docker network inspect を使います。

$ docker network inspect bridge
[
   {
       "Name": "bridge",
       "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
       "Scope": "local",
       "Driver": "bridge",
       "IPAM": {
           "Driver": "default",
           "Config": [
               {
                   "Subnet": "172.17.0.1/16",
                   "Gateway": "172.17.0.1"
               }
           ]
       },
       "Containers": {},
       "Options": {
           "com.docker.network.bridge.default_bridge": "true",
           "com.docker.network.bridge.enable_icc": "true",
           "com.docker.network.bridge.enable_ip_masquerade": "true",
           "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
           "com.docker.network.bridge.name": "docker0",
           "com.docker.network.driver.mtu": "9001"
       }
   }
]

Engine は自動的にネットワーク上に SubnetGateway を作成します。 docker run コマンドは新しいコンテナにたいして自動的にこのネットワークを割り当てます。

$ docker run -itd --name=container1 busybox
3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c

$ docker run -itd --name=container2 busybox
94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c

2つのコンテナを実行してから、再びこのブリッジ・ネットワークを参照し、直近のコンテナのネットワークがどのようになっているか見てみましょう。コンテナの ID が表示されるようになります。

$ docker network inspect bridge
{[
    {
        "Name": "bridge",
        "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.0.1/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Containers": {
            "3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c": {
                "EndpointID": "647c12443e91faf0fd508b6edfe59c30b642abb60dfab890b4bdccee38750bc1",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c": {
                "EndpointID": "b047d090f446ac49747d3c37d63e4307be745876db7f0ceef7b311cbba615f48",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "9001"
        }
    }
]

上の docker network inspect コマンドは、接続しているコンテナと特定のネットワーク上にある各々のネットワークを全て表示します。デフォルト・ネットワークのコンテナは、IP アドレスを使って相互に通信できます。デフォルトのネットワーク・ブリッジ上では、Docker は自動的なサービス・ディスカバリをサポートしていません。このデフォルト・ブリッジ・ネットワーク上でコンテナ名を使って通信をしたい場合、コンテナ間の接続にはレガシー(訳者注:古い)の docker run --link オプションを使う必要があります。

実行しているコンテナに attach することにより、設定を調査できます。

$ docker attach container1

/ # ifconfig
ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:16 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1296 (1.2 KiB)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

この bridge ネットワークにおけるコンテナの接続性をテストするため、3秒間 ping を実行します。

/ # ping -w3 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.096 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.074 ms

--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.074/0.083/0.096 ms

最後に cat コマンドを使い、 container1 のネットワーク設定を確認します。

/ # cat /etc/hosts
172.17.0.2   3386a527aa08
127.0.0.1    localhost
::1  localhost ip6-localhost ip6-loopback
fe00::0      ip6-localnet
ff00::0      ip6-mcastprefix
ff02::1      ip6-allnodes
ff02::2      ip6-allrouters

container1 からデタッチするには、 CTRL-p CTRL-q を使って離れます。それから container2 にアタッチし、3つのコマンドを繰り返します。

$ docker attach container2

/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03
          inet addr:172.17.0.3  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1166 (1.1 KiB)  TX bytes:1026 (1.0 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ping -w3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.067 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.072 ms

--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.067/0.071/0.075 ms
/ # cat /etc/hosts
172.17.0.3   94447ca47985
127.0.0.1    localhost
::1  localhost ip6-localhost ip6-loopback
fe00::0      ip6-localnet
ff00::0      ip6-mcastprefix
ff02::1      ip6-allnodes
ff02::2      ip6-allrouters

デフォルトの docker0 ブリッジ・ネットワークは、ポート・マッピングの使用と、 docker run --link によって docker0 ネットワーク上にあるコンテナ間の通信を可能とするものです。これらの技術はセットアップが面倒であり、間違いしがちです。この技術はまだ利用可能ですが、これらを使わず、その代わりに自分自身でブリッジ・ネットワークを定義するほうが望ましいです。

ユーザ定義ネットワーク

コンテナのより優れた分離のために、自分自身でユーザ定義ネットワーク(user-defined networks)を作成できます。Docker はこれらネットワークを作成するための、複数の ネットワーク・ドライバ を標準提供しています。新しい ブリッジ・ネットワークオーバレイ・ネットワーク を作成できます。また、ネットワーク・プラグインリモート・ネットワーク を書くことで、自分自身でも定義できます。

ネットワークは複数作成できます。コンテナを1つ以上のネットワークに追加できます。コンテナの通信はネットワーク内だけでなく、ネットワークを交差できます。コンテナが2つのネットワークにアタッチされている場合、どちらのネットワークに対しても通信可能です。

次のいくつかのセクションでは、各 Docker 内蔵ネットワーク・ドライバに関するより詳細を扱います。

ブリッジ・ネットワーク

最も簡単なユーザ定義ネットワークは、 bridge ネットワークの作成です。このネットワークは過去の docker0 ネットワークと似ています。いくつかの新機能が追加されていますが、古い機能のいくつかは利用できません。

$ docker network create --driver bridge isolated_nw
1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b

$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.21.0.0/16",
                    "Gateway": "172.21.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

$ docker network ls
NETWORK ID          NAME                DRIVER
9f904ee27bf5        none                null
cf03ee007fb4        host                host
7fca4eb8c647        bridge              bridge
c5ee82f76de3        isolated_nw         bridge

ネットワークを作成したら、接続のために、コンテナ起動時に docker run --net=<ネットワーク名> オプションを使います。

$ docker run --net=isolated_nw -itd --name=container3 busybox
885b7b4f792bae534416c95caa35ba272f201fa181e18e59beba0c80d7d77c1d

$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {
            "885b7b4f792bae534416c95caa35ba272f201fa181e18e59beba0c80d7d77c1d": {
                "EndpointID": "514e1b419074397ea92bcfaa6698d17feb62db49d1320a27393b853ec65319c3",
                "MacAddress": "02:42:ac:15:00:02",
                "IPv4Address": "172.21.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]

このネットワークの中で起動したコンテナは、Docker ホスト上の他のコンテナとは分離されています。ネットワーク内の各コンテナは速やかに通信が可能です。しかし、コンテナ自身が含まれるネットワークは外部のネットワークと分離されています。

../../../_images/bridge_network.png

ユーザ定義ブリッジ・ネットワークの内部では、リンク機能はサポートされません。ですが、このネットワーク上にあるコンテナのポートは公開可能です。外側のネットワークを利用するときに、一部としての bridge ネットワーク作成が役立つでしょう。

../../../_images/network_access.png

ブリッジ・ネットワークは、単一ホスト上で比較的小さなネットワークの実行時に使いやすいです。それだけでなく、とりわけ大きなネットワークでは overlay ネットワークも作成できます

オーバレイ・ネットワーク

Docker の overlay (オーバレイ)ネットワーク・ドライバは、複数ホストのネットワーキングにネイティブに対応する革新的なものです。このサポートは libnetwork 、 VXLAN を基盤とした内蔵オーバレイ・ネットワーク・ドライバ、Docker の libkv ライブラリによる成果です。

overlay ネットワークはキーバリュー・ストア・サービスを必要とします。現時点で Docker の libkv がサポートしているのは、Consul、Etcd、Zookeeper(分散ストア)です。ネットワークを作成する前に、キーバリュー・ストア・サービスを選び、設定する必要があります。そして、Docker ホストによって、ネットワークとサービスが通信できるようにするでしょう。

../../../_images/key-value.png

ネットワークの各ホストは、それぞれで Docker エンジンを動かす必要があります。最も簡単なのは Docker Machine を使ってホストをプロビジョンする方法です。

../../../_images/engine-on-net.png

ホスト間で以下のポートをオープンにすべきです。

プロトコル Port 説明
udp 4789 データ用 (VXLAN)
tcp/udp 7946 管理用

使用するキーバリュー・ストアによっては、追加ポートが必要になる場合があります。各ベンダーのドキュメントを確認氏、必要なポートを開いてください。

複数のマシンをプロビジョンしたあとは、Docker Swarm を使って Swarm とディスカバリ・サービスを同様に迅速に入れられます。

オーバレイ・ネットワークを作成するには、各々の Docker Engine 上の daemon のオプションで、 overlay ネットワークを設定します。そこには2つの設定オプションがあります:

オプション 説明
--cluster-store=PROVIDER://URL キーバリュー・サービスの場所を指定
–cluster-advertise=HOST_IP|HOST_IFACE:PORT クラスタ用に使うホストのインターフェース用 IP アドレス
--cluster-store-opt=KVSのオプション TLS 証明書やディスカバリ間隔の調整のようなオプション。

overlay ネットワークを Swarm のマシン上に作成します。

$ docker network create --driver overlay my-multi-host-network

この結果、複数のホストをまたぐ1つのネットワークができます。 overlay ネットワークはコンテナに対して、完全なる分離機能を提供します。

../../../_images/overlay-network.png

以後、各ホスト上でコンテナ起動時にこのネットワーク名を指定します。

$ docker run -itd --net=my-multi-host-network busybox

接続したあと、ネットワーク内の各コンテナ全てにアクセス可能となります。このとき、コンテナがどこのホスト上で起動しているか気にする必要はありません。

../../../_images/overlay-network-final.png

自分自身で試したい場合は、こちらの overlay 導入ガイド をご覧ください。

カスタム・ネットワーク・プラグイン

必要があれば、自分自身でネットワーク・ドライバ・プラグインを書けます。ネットワーク・ドライバ・プラグインは Docker のプラグイン基盤を使います。この基盤を使い、Docker デーモン が動作する同じ Docker ホストでプラグインをプロセスとして実行します。

ネットワーク・プラグインは、他のプラグインと同様、いくつかの制約やインストール時のルールがあります。全てのプラグインはプラグイン API を利用します。これらはインストール、開始、停止、有効化といったライフサイクル全般に亘ります。

カスタム・ネットワーク・ドライバを作成してインストールした後は、内蔵ネットワーク・ドライバと同じように扱えます。例:

$ docker network create --driver weave mynet

内部を確認できますし、さらにコンテナを追加したり、いろいろできます。もちろん、プラグイン毎に異なった技術やフレームワークを使うこともあるでしょう。カスタム・ネットワークは Docker の標準ネットワークが持たない機能を実装できます。プラグインの書き方に関する詳細情報は、 Docker 拡張 または ネットワーク・ドライバ・プラグインの書き方 をお読みください。

Docker 内蔵 DNS サーバ

Docker デーモンは内蔵 DNS サーバを実行し、ユーザ定義ネットワーク上でコンテナがサービス・ディスカバリを自動的に行えるようにします。コンテナから名前解決のリクエストがあれば、内蔵 DNS サーバを第一に使います。リクエストがあっても内蔵 DNS サーバが名前解決できなければ、外部の DNS サーバにコンテナからのリクエストを手の鮨ます。割り当てできるのはコンテナの作成時だけです。内蔵 DNS サーバが到達可能なのは 127.0.0.11 のみであり、コンテナの resolv.conf に書かれます。ユーザ定義ネットワーク上の内蔵 DNS サーバに関しては ユーザ定義ネットワーク用の内蔵 DNS サーバ をご覧ください。

リンク機能

Docker ネットワーク機能より以前は、Docker リンク機能を使いコンテナをお互いに発見したり、特定のコンテナから別のコンテナに安全に情報を送信できました。Docker ネットワークを導入すると、自動的にコンテナは名前で見つけることができます。しかし、デフォルトの docker0 ブリッジ・ネットワークとユーザ定義ネットワークには違いがあるため、まだリンク機能を使うこともできます。より詳しい情報については、 古いリンク機能 のデフォルト bridge ネットワークのリンク機能をご覧ください。ユーザ定義ネットワークでリンク機能を使うには ユーザ定義ネットワークでコンテナをリンク をご覧ください。