スタンドアロンなコンテナーのネットワーク

ここに示すチュートリアルは、スタンドアロンの Docker コンテナーに対するネットワークを扱います。 Swarm サービスにおけるネットワークについては Swarm サービスにおけるネットワーク を参照してください。 Docker ネットワークの全般的なことを確認したい場合は、 ネットワーク概要 を参照してください。

このトピックには 2 つのチュートリアルがあります。 それぞれは Linux、Windows、Mac 上において実行することができます。 ただし Mac の場合は、2 つめの Docker ホストをどこか別に用意することが必要になります。

  • デフォルトのブリッジネットワーク利用 では、Docker が自動的に設定するデフォルトの bridge ネットワークの利用方法を示します。 このネットワークは、本番環境向けには適していません。

  • ユーザー定義のブリッジネットワーク利用 では、独自にブリッジネットワークを生成して、同一の Docker ホスト上で稼動する複数コンテナーに接続して利用する方法を示します。 本番環境においてスタンドアロンコンテナーを稼動させる場合には、この方法が推奨されます。

Swarm サービスにおいて利用されるのは、一般的には オーバーレイネットワーク です。 このオーバーレイネットワークは、スタンドアロンコンテナーに対しても利用することができます。 このことは オーバーレイネットワークのチュートリアル において触れています。

デフォルトのブリッジネットワーク利用

以下の例では、2 つのalpineコンテナーを同じ Docker ホスト上に稼動させます。 そしてテストを行ってみて、コンテナー同士がどのようにやりとりを行うかを見ていきます。 Docker がインストール済みであり、起動していることを確認してください。

  1. ターミナル画面を開きます。 まず初めに、現在のネットワーク一覧を確認しておきます。 ネットワークをまったく追加せず、Docker デーモン上において Swarm の初期化も行っていなければ、以下のような表示になるはずです。 複数のネットワークが表示されるはずであり、最低で以下のものがあるはずです。 (ネットワーク ID は異なります。)

    $ docker network ls
    
    NETWORK ID          NAME                DRIVER              SCOPE
    17e324f45964        bridge              bridge              local
    6ed54d316334        host                host                local
    7092879f2cc8        none                null                local
    

    デフォルトの bridge ネットワークが一覧に表示されます。 これとともに hostnone があります。 この 2 つは完全なネットワークではありませんが、コンテナーを起動して Docker デーモンホストのネットワークに直接接続するために、あるいはネットワークデバイスのないコンテナーを起動するために必要となります。 このチュートリアルでは、2 つのコンテナーを bridge ネットワークに接続します。

  2. 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
    
  3. 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 アドレスの情報もあります(alpine1172.17.0.2alpine2172.17.0.3 となっています)。

  4. コンテナーはバックグラウンドで実行しています。 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 のアドレスと同じです。

  5. 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
    
  6. そこで 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'
    
  7. alpine1 を停止させることなくデタッチします。 これはデタッチを行うキー操作、つまり CTRL+pCTRL+q により行います(CTRL を押したまま、pq を順に押します)。 この後 alpine2 に対して同じことをするなら、手順の 4、5、6 をもう一度行います。 alpine1 のところは alpine2 に変えて実施します。

  8. 2 つのコンテナーを停止させ削除します。

    $ docker container stop alpine1 alpine2
    $ docker container rm alpine1 alpine2
    

デフォルトの bridge ネットワークは、本番環境向けとしては推奨されない点を覚えておいてください。 ユーザー定義のブリッジネットワークについては、 次のチュートリアル に進んでください。

ユーザー定義のブリッジネットワーク利用

以下の例では、すでに生成している 2 つの alpine コンテナーをもう一度使います。 ただしこれをアタッチするのは、alpine-net という名前のユーザー定義ネットワークです。 もうデフォルトの bridge ネットワークへの接続は行いません。 そして 3 つめの alpine コンテナーを用意します。 これは bridge ネットワークに接続させるものの alpine-net には接続しません。 さらに 4 つめの alpine コンテナーを、その両方のネットワークに接続するようにします。

  1. alpine-net ネットワークを生成します。 --driver bridge フラグは不要です。 なぜならそれがデフォルトであるからです。 ただし以下の例では、指定方法を示すために含めます。

    $ docker network create --driver bridge alpine-net
    
  2. 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 アドレスの実際はシステムによって異なります。

  3. 4 つのコンテナーを生成します。 それぞれの --network フラグに注目してください。 docker run コマンドの実行において、接続指定できるネットワークはただ 1 つです。 したがって alpine4bridge にも接続させるために、後から 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
    
  4. 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": {}
        }
    ]
    

    alpine3alpine4bridge ネットワークに接続されています。

    $ 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": {}
        }
    ]
    

    alpine1alpine2alpine4alpine-net ネットワークに接続されています。

  5. alpine-net のようなユーザー定義ネットワークでは、IP アドレスによる通信が可能です。 さらにコンテナー名から IP アドレスを解決することもできます。 この機能のことを自動サービス検出 (automatic service discovery) と呼びます。 では alpine1 に接続して、いろいろテストしてみます。 alpine1alpine2alpine4(そして 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
    
  6. alpine1 から alpine3 へはまったく接続できないはずです。 alpine3alpine-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+pCTRL+q を行います(CTRL を押したまま pq を順に押します)。

  7. 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
    
  8. 確認の最後として、どのコンテナーもインターネットには接続できるはずですから、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
    
  9. コンテナーすべてを停止し削除します。 そして alpine-net ネットワークを削除します。

    $ docker container stop alpine1 alpine2 alpine3 alpine4
    
    $ docker container rm alpine1 alpine2 alpine3 alpine4
    
    $ docker network rm alpine-net
    

その他のネットワークチュートリアル