スタンドアロンなコンテナーのネットワーク
ここに示すチュートリアルは、スタンドアロンの 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 ash2 つのコンテナーが実際に開始されたことを確認します。
$ 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 alpine1bridgeネットワークを参照して、どのコンテナーがこれに接続しているかを確認します。$ 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 forever1 つめのインターフェースはループバックデバイスです。 今はこれを無視します。 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-netDocker のネットワーク一覧を表示します。
$ docker network ls NETWORK ID NAME DRIVER SCOPE e9261a8c9a19 alpine-net bridge local 17e324f45964 bridge bridge local 6ed54d316334 host host local 7092879f2cc8 none null localalpine-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 alpine1bridgeネットワークと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 msalpine1から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