スタンドアロンなコンテナーのネットワーク
ここに示すチュートリアルは、スタンドアロンの Docker コンテナーに対するネットワークを扱います。 Swarm サービスにおけるネットワークについては Swarm サービスにおけるネットワーク を参照してください。 Docker ネットワークの全般的なことを確認したい場合は、 ネットワーク概要 を参照してください。
このトピックには 2 つのチュートリアルがあります。 それぞれは Linux、Windows、Mac 上において実行することができます。 ただし Mac の場合は、2 つめの Docker ホストをどこか別に用意することが必要になります。
デフォルトのブリッジネットワーク利用 では、Docker が自動的に設定するデフォルトの
bridge
ネットワークの利用方法を示します。 このネットワークは、本番環境向けには適していません。ユーザー定義のブリッジネットワーク利用 では、独自にブリッジネットワークを生成して、同一の Docker ホスト上で稼動する複数コンテナーに接続して利用する方法を示します。 本番環境においてスタンドアロンコンテナーを稼動させる場合には、この方法が推奨されます。
Swarm サービスにおいて利用されるのは、一般的には オーバーレイネットワーク です。 このオーバーレイネットワークは、スタンドアロンコンテナーに対しても利用することができます。 このことは オーバーレイネットワークのチュートリアル において触れています。
デフォルトのブリッジネットワーク利用
以下の例では、2 つのalpine
コンテナーを同じ Docker ホスト上に稼動させます。
そしてテストを行ってみて、コンテナー同士がどのようにやりとりを行うかを見ていきます。
Docker がインストール済みであり、起動していることを確認してください。
ターミナル画面を開きます。 まず初めに、現在のネットワーク一覧を確認しておきます。 ネットワークをまったく追加せず、Docker デーモン上において Swarm の初期化も行っていなければ、以下のような表示になるはずです。 複数のネットワークが表示されるはずであり、最低で以下のものがあるはずです。 (ネットワーク ID は異なります。)
$ docker network ls NETWORK ID NAME DRIVER SCOPE 17e324f45964 bridge bridge local 6ed54d316334 host host local 7092879f2cc8 none null local
デフォルトの
bridge
ネットワークが一覧に表示されます。 これとともにhost
とnone
があります。 この 2 つは完全なネットワークではありませんが、コンテナーを起動して Docker デーモンホストのネットワークに直接接続するために、あるいはネットワークデバイスのないコンテナーを起動するために必要となります。 このチュートリアルでは、2 つのコンテナーをbridge
ネットワークに接続します。alpine
コンテナーを 2 つ起動してash
を実行します。 Alpine のデフォルトシェルがbash
ではなくash
です。-dit
フラグは、コンテナーをデタッチモードで(バックグラウンドで)実行し、対話を行い(入力を可能とし)、TTY を利用する(入出力が確認できる)ことを意味します。 デタッチモードで起動するため、コンテナーに即座に接続されるわけではありません。 その前にコンテナー ID が出力されます。--network
フラグを何も指定しなかったので、コンテナーはデフォルトのbridge
ネットワークに接続されます。$ docker run -dit --name alpine1 alpine ash $ docker run -dit --name alpine2 alpine ash
2 つのコンテナーが実際に開始されたことを確認します。
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 602dbf1edc81 alpine "ash" 4 seconds ago Up 3 seconds alpine2 da33b7aa74b0 alpine "ash" 17 seconds ago Up 16 seconds alpine1
bridge
ネットワークを参照して、どのコンテナーがこれに接続しているかを確認します。$ docker network inspect bridge [ { "Name": "bridge", "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10", "Created": "2017-06-22T20:27:43.826654485Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Containers": { "602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c": { "Name": "alpine2", "EndpointID": "03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" }, "da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168": { "Name": "alpine1", "EndpointID": "46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/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": "1500" }, "Labels": {} } ]
上の方に
bridge
ネットワークに関する情報が一覧表示されます。 Docker ホストとbridge
ネットワーク間のゲートウェイに対する IP アドレス(172.17.0.1
)も表示されています。Containers
キーの配下に、接続されているコンテナーがそれぞれ表示されています。 そこには IP アドレスの情報もあります(alpine1
が172.17.0.2
、alpine2
が172.17.0.3
となっています)。コンテナーはバックグラウンドで実行しています。
docker attach
コマンドを使ってalpine1
に接続してみます。$ docker attach alpine1 / #
プロンプトが
#
に変わりました。 これはコンテナー内のroot
ユーザーであることを意味します。ip addr show
コマンドを使って、コンテナー内部からalpine1
のネットワークインターフェースを見てみます。# ip addr show 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 27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever
1 つめのインターフェースはループバックデバイスです。 今はこれを無視します。 2 つめのインターフェースの IP アドレスは
172.17.0.2
となっています。 前の手順で確認したalpine1
のアドレスと同じです。alpine1
の内部からgoogle.com
への ping を行ってインターネットに接続してみます。-c 2
フラグにより 2 回だけping
を行います。# ping -c 2 google.com PING google.com (172.217.3.174): 56 data bytes 64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.841 ms 64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.897 ms --- google.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 9.841/9.869/9.897 ms
そこで 2 つめのコンテナーに対して ping してみます。 最初は IP アドレス
172.17.0.3
を使って ping します。# ping -c 2 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.086 ms 64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.094 ms --- 172.17.0.3 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.086/0.090/0.094 ms
成功しました。 次に
alpine2
コンテナーに向けて、コンテナー名により ping をしてみます。 これは失敗します。# ping -c 2 alpine2 ping: bad address 'alpine2'
alpine1
を停止させることなくデタッチします。 これはデタッチを行うキー操作、つまりCTRL
+p
、CTRL
+q
により行います(CTRL
を押したまま、p
とq
を順に押します)。 この後alpine2
に対して同じことをするなら、手順の 4、5、6 をもう一度行います。alpine1
のところはalpine2
に変えて実施します。2 つのコンテナーを停止させ削除します。
$ docker container stop alpine1 alpine2 $ docker container rm alpine1 alpine2
デフォルトの bridge
ネットワークは、本番環境向けとしては推奨されない点を覚えておいてください。
ユーザー定義のブリッジネットワークについては、
次のチュートリアル に進んでください。
ユーザー定義のブリッジネットワーク利用
以下の例では、すでに生成している 2 つの alpine
コンテナーをもう一度使います。
ただしこれをアタッチするのは、alpine-net
という名前のユーザー定義ネットワークです。
もうデフォルトの bridge
ネットワークへの接続は行いません。
そして 3 つめの alpine
コンテナーを用意します。
これは bridge
ネットワークに接続させるものの alpine-net
には接続しません。
さらに 4 つめの alpine
コンテナーを、その両方のネットワークに接続するようにします。
alpine-net
ネットワークを生成します。--driver bridge
フラグは不要です。 なぜならそれがデフォルトであるからです。 ただし以下の例では、指定方法を示すために含めます。$ docker network create --driver bridge alpine-net
Docker のネットワーク一覧を表示します。
$ docker network ls NETWORK ID NAME DRIVER SCOPE e9261a8c9a19 alpine-net bridge local 17e324f45964 bridge bridge local 6ed54d316334 host host local 7092879f2cc8 none null local
alpine-net
ネットワークを確認します。 そこから IP アドレスがわかります。 また接続されているコンテナーが 1 つもないことがわかります。$ docker network inspect alpine-net [ { "Name": "alpine-net", "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec", "Created": "2017-09-25T21:38:12.620046142Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Containers": {}, "Options": {}, "Labels": {} } ]
ネットワークのゲートウェイは
172.18.0.1
となっています。 デフォルトのブリッジネットワークのときとは違っていて、その際には172.17.0.1
でした。 IP アドレスの実際はシステムによって異なります。4 つのコンテナーを生成します。 それぞれの
--network
フラグに注目してください。docker run
コマンドの実行において、接続指定できるネットワークはただ 1 つです。 したがってalpine4
をbridge
にも接続させるために、後からdocker network connect
を実行することが必要になります。$ docker run -dit --name alpine1 --network alpine-net alpine ash $ docker run -dit --name alpine2 --network alpine-net alpine ash $ docker run -dit --name alpine3 alpine ash $ docker run -dit --name alpine4 --network alpine-net alpine ash $ docker network connect bridge alpine4
コンテナーすべてが実行していることを確認します。
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 156849ccd902 alpine "ash" 41 seconds ago Up 41 seconds alpine4 fa1340b8d83e alpine "ash" 51 seconds ago Up 51 seconds alpine3 a535d969081e alpine "ash" About a minute ago Up About a minute alpine2 0a02c449a6e9 alpine "ash" About a minute ago Up About a minute alpine1
bridge
ネットワークとalpine-net
ネットワークを再度確認してみます。$ docker network inspect bridge [ { "Name": "bridge", "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10", "Created": "2017-06-22T20:27:43.826654485Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Containers": { "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": { "Name": "alpine4", "EndpointID": "7277c5183f0da5148b33d05f329371fce7befc5282d2619cfb23690b2adf467d", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" }, "fa1340b8d83eef5497166951184ad3691eb48678a3664608ec448a687b047c53": { "Name": "alpine3", "EndpointID": "5ae767367dcbebc712c02d49556285e888819d4da6b69d88cd1b0d52a83af95f", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/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": "1500" }, "Labels": {} } ]
alpine3
とalpine4
はbridge
ネットワークに接続されています。$ docker network inspect alpine-net [ { "Name": "alpine-net", "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec", "Created": "2017-09-25T21:38:12.620046142Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Containers": { "0a02c449a6e9a15113c51ab2681d72749548fb9f78fae4493e3b2e4e74199c4a": { "Name": "alpine1", "EndpointID": "c83621678eff9628f4e2d52baf82c49f974c36c05cba152db4c131e8e7a64673", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", "IPv6Address": "" }, "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": { "Name": "alpine4", "EndpointID": "058bc6a5e9272b532ef9a6ea6d7f3db4c37527ae2625d1cd1421580fd0731954", "MacAddress": "02:42:ac:12:00:04", "IPv4Address": "172.18.0.4/16", "IPv6Address": "" }, "a535d969081e003a149be8917631215616d9401edcb4d35d53f00e75ea1db653": { "Name": "alpine2", "EndpointID": "198f3141ccf2e7dba67bce358d7b71a07c5488e3867d8b7ad55a4c695ebb8740", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "172.18.0.3/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ]
alpine1
、alpine2
、alpine4
はalpine-net
ネットワークに接続されています。alpine-net
のようなユーザー定義ネットワークでは、IP アドレスによる通信が可能です。 さらにコンテナー名から IP アドレスを解決することもできます。 この機能のことを自動サービス検出 (automatic service discovery) と呼びます。 ではalpine1
に接続して、いろいろテストしてみます。alpine1
はalpine2
とalpine4
(そしてalpine1
そのもの)の IP アドレスが解決できなければなりません。メモ
自動サービス検出 (automatic service discovery) によって解決される名前は、カスタム指定した名前のみであって、デフォルトで自動的に生成されたコンテナー名に対しては行われません。
$ docker container attach alpine1 # ping -c 2 alpine2 PING alpine2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.085 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.090 ms --- alpine2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.085/0.087/0.090 ms # ping -c 2 alpine4 PING alpine4 (172.18.0.4): 56 data bytes 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.076 ms 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.091 ms --- alpine4 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.076/0.083/0.091 ms # ping -c 2 alpine1 PING alpine1 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.026 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.054 ms --- alpine1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.026/0.040/0.054 ms
alpine1
からalpine3
へはまったく接続できないはずです。alpine3
はalpine-net
ネットワーク上にないからです。# ping -c 2 alpine3 ping: bad address 'alpine3'
それだけでなく
alpine1
からalpine3
へは、IP アドレスを利用しても接続できません。docker network inspect
を使ったbridge
ネットワークの確認時の出力結果をもう一度確認してください。alpine3
の IP アドレスは172.17.0.2
であったはずです。 そこで ping を行ってみます。# ping -c 2 172.17.0.2 PING 172.17.0.2 (172.17.0.2): 56 data bytes --- 172.17.0.2 ping statistics --- 2 packets transmitted, 0 packets received, 100% packet loss
デタッチキー操作により
alpine1
をデタッチします。CTRL
+p
、CTRL
+q
を行います(CTRL
を押したままp
とq
を順に押します)。alpine4
は、デフォルトのbridge
ネットワークとalpine-net
ネットワークの両方に接続していました。 このコンテナーは別のコンテナーすべてに接続できるはずです。 ただしそれを行うにはalpine3
の IP アドレスを知っておく必要があります。 そこでalpine3
にアタッチして、いろいろ確認してみます。$ docker container attach alpine4 # ping -c 2 alpine1 PING alpine1 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.082 ms --- alpine1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.074/0.078/0.082 ms # ping -c 2 alpine2 PING alpine2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.075 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.080 ms --- alpine2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.075/0.077/0.080 ms # ping -c 2 alpine3 ping: bad address 'alpine3' # ping -c 2 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.089 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms --- 172.17.0.2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.075/0.082/0.089 ms # ping -c 2 alpine4 PING alpine4 (172.18.0.4): 56 data bytes 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.033 ms 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.064 ms --- alpine4 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.033/0.048/0.064 ms
確認の最後として、どのコンテナーもインターネットには接続できるはずですから、
google.com
への ping を行ってみます。alpine4
はすでにアタッチしていますから、そこから始めます。 そしてalpine4
のデタッチの後にalpine3
(これは唯一bridge
ネットワークに接続しているものです)に接続して、同じことを確認します。 最終的に(alpine-net
ネットワークにのみ接続している)alpine1
への接続と同様の確認まで進めます。# ping -c 2 google.com PING google.com (172.217.3.174): 56 data bytes 64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.778 ms 64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.634 ms --- google.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 9.634/9.706/9.778 ms CTRL+p CTRL+q $ docker container attach alpine3 # ping -c 2 google.com PING google.com (172.217.3.174): 56 data bytes 64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.706 ms 64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.851 ms --- google.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 9.706/9.778/9.851 ms CTRL+p CTRL+q $ docker container attach alpine1 # ping -c 2 google.com PING google.com (172.217.3.174): 56 data bytes 64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.606 ms 64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.603 ms --- google.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 9.603/9.604/9.606 ms CTRL+p CTRL+q
コンテナーすべてを停止し削除します。 そして
alpine-net
ネットワークを削除します。$ docker container stop alpine1 alpine2 alpine3 alpine4 $ docker container rm alpine1 alpine2 alpine3 alpine4 $ docker network rm alpine-net