network コマンドを使う

この記事ではネットワーク・サブコマンドの例を扱います。このサブコマンドはDocket ネットワークを相互に扱い、コンテナをネットワークに配置します。コマンドは Docker エンジン CLI を通して利用可能です。コマンドとは以下の通りです。

  • docker network create
  • docker network connect
  • docker network ls
  • docker network rm
  • docker network disconnect
  • docker network inspect

このセクションの例に取り組む前に、 Docker ネットワークの理解 を読むのは必要ではなくとも良い考えです。なお、この例では bridge ネットワークを使用するため、すぐに試せます。 overlay ネットワークを試したいのであれば、 マルチホスト・ネットワーキングを始める をご覧ください。

ネットワークの作成

Docker Engine をインストールしたら、Docker Engine は自動的に bridge ネットワークを作成します。このネットワークとは、Docker Engine が従来使ってきた docker0 ブリッジに相当します。このデフォルトのネットワークだけでなく、自分で bridge (ブリッジ)ネットワークや overlay (オーバレイ)ネットワークを作成可能です。

bridge ネットワークは Docker エンジンの実行ホスト環境上に存在します。 overlay ネットワークは、複数のホスト上で動くエンジンを横断します。 docker network create を実行する時、ネットワーク名だけ指定したら、自動的にブリッジ・ネットワークを作成します。

$ docker network create simple-network
69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a
$ docker network inspect simple-network
[
    {
        "Name": "simple-network",
        "Id": "69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.22.0.0/16",
                    "Gateway": "172.22.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

overlay ネットワークの場合は、ブリッジ・ネットワークとは異なります。作成前にいくつかの事前準備が必要です。事前準備は次の項目です。

  • キーバリュー・ストアへのアクセス。エンジンがサポートするキーバリュー・ストアは Consul、Etcd、ZooKeeper(分散ストア)です。
  • ホストのクラスタが、キーバリュー・ストアへ接続できること。
  • 各ホスト上のエンジン daemon に、 Swarm クラスタとしての適切な設定をすること。

overlay ネットワークがサポートする dockerd のオプションは、次の通りです。

  • --cluster-store
  • --cluster-store-opt
  • --cluster-advertise

また、必要がなくてもクラスタ管理用に Docker Swarm をインストールするのも良い考えでしょう。Swarm はクラスタの設定を手助けするために、洗練されたディスカバリとサーバ管理機能を持っています。

ネットワーク作成時、Docker Engine はデフォルトでサブネットが重複しないネットワークを作成します。このデフォルトの挙動は変更できます。特定のサブネットワークを直接指定するには --subnet オプションを使います。 bridge ネットワーク上では1つだけサブネットを作成できます。 overlay ネットワークでは、複数のサブネットをサポートしています。

注釈

ネットワークの作成時は --subnet オプションの指定を強く推奨します。 --subnet を指定しなければ、docker デーモンはネットワークに対してサブネットを自動的に割り当てます。その時、Docker が管理していない基盤上の別サブネットと重複する可能性があります。このような重複により、コンテナがネットワークに接続するときに問題や障害を引き起こします。

--subnet オプションの他にも、 --gateway --ip-range --aux-address オプションが指定可能です。

$ docker network create -d overlay \
  --subnet=192.168.0.0/16 \
  --subnet=192.170.0.0/16 \
  --gateway=192.168.0.100 \
  --gateway=192.170.0.100 \
  --ip-range=192.168.1.0/24 \
  --aux-address a=192.168.1.5 --aux-address b=192.168.1.6 \
  --aux-address a=192.170.1.5 --aux-address b=192.170.1.6 \
  my-multihost-network

サブネットワークが重複しないように注意してください。重複したらネットワーク作成が失敗し、Docker Engine はエラーを返します。

カスタム・ネットワークの作成時、デフォルトのネットワーク・ドライバ(例: bridge )は追加オプションを指定できます。dokcer0 ブリッジにおいては、Docker デーモンのフラグで指定するのと同等の以下の設定が利用できます。

オプション 同等 説明
com.docker.network.bridge.name Linux ブリッジ作成時に使うブリッジ名
com.docker.network.bridge.enable_ip_masquerade --ip-masq IP マスカレードを有効化
com.docker.network.bridge.enable_icc --icc Docker 内部におけるコンテナの接続性を有効化・無効化
com.docker.network.bridge.host_binding_ipv4 --ip コンテナのポートをバインドする(割り当てる)デフォルトの IP
com.docker.network.mtu --mtu コンテナのネットワーク MTU を設定

docker network create 実行時、以下の引数をあらゆるネットワーク・ドライバで指定できます。

引数 同等 説明
--internal ネットワークから外部へのアクセスを制限
--ipv6 --ipv6 IPv6 ネットワーク機能の有効化

例えば、 -o または --opt オプションを使い、ポートを公開用に割り当てる IP アドレスを指定しましょう。

$ docker network create -o "com.docker.network.bridge.host_binding_ipv4"="172.23.0.1" my-network
b1a086897963e6a2e7fc6868962e55e746bee8ad0c97b54a5831054b5f62672a
$ docker network inspect my-network
[
    {
        "Name": "my-network",
        "Id": "b1a086897963e6a2e7fc6868962e55e746bee8ad0c97b54a5831054b5f62672a",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.23.0.0/16",
                    "Gateway": "172.23.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.host_binding_ipv4": "172.23.0.1"
        }
    }
]
$ docker run -d -P --name redis --net my-network redis
bafb0c808c53104b2c90346f284bda33a69beadcab4fc83ab8f2c5a4410cd129
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                        NAMES
bafb0c808c53        redis               "/entrypoint.sh redis"   4 seconds ago       Up 3 seconds        172.23.0.1:32770->6379/tcp   redis

コンテナに接続

コンテナは1つまたは複数のネットワークに対して、動的に接続できます。これらのネットワークは、同じネットワーク・ドライバの場合もあれば、異なるバックエンドの場合もあります。接続後は、コンテナから他のコンテナに IP アドレスまたはコンテナ名で通信できるようになります。

overlay ネットワークやカスタム・プラグインの場合は、複数のホストへの接続性をサポートしており、コンテナは同一ホストで作成されたマルチホスト・ネットワークだけでなく、異なったホスト上で作成された環境とも同様に通信可能です。

ここでは例として、2つのコンテナを作成します。

$ docker run -itd --name=container1 busybox
18c062ef45ac0c026ee48a83afa39d25635ee5f02b58de4abc8f467bcaa28731

$ docker run -itd --name=container2 busybox
498eaaaf328e1018042c04b2de04036fc04719a6e39a097a4f4866043a2c2152

それから、分離用の bridge ネットワークを作成します。

$ docker network create -d bridge --subnet 172.25.0.0/16 isolated_nw
06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8

このネットワークに container2 を追加し、ネットワークへの接続性を調査( inspect )します。

$ docker network connect isolated_nw container2
$ docker network inspect isolated_nw
[[
    {
        "Name": "isolated_nw",
        "Id": "06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.21.0.0/16",
                    "Gateway": "172.21.0.1/16"
                }
            ]
        },
        "Containers": {
            "90e1f3ec71caf82ae776a827e0712a68a110a3f175954e5bd4222fd142ac9428": {
                "Name": "container2",
                "EndpointID": "11cedac1810e864d6b1589d92da12af66203879ab89f4ccd8c8fdaa9b1c48b1d",
                "MacAddress": "02:42:ac:19:00:02",
                "IPv4Address": "172.25.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]

Docker Engineが自動的に container2 に IP アドレスを割り当てているのが分かります。もしもネットワーク作成時に --subnet を指定していたならば、Docker Engine は指定されたサブネットから IP アドレスを取得します。次に3つめのコンテナを起動します。このネットワークにコンテナを接続するには、 docker run コマンドで --net オプションを使います。

$ docker run --net=isolated_nw --ip=172.25.3.3 -itd --name=container3 busybox
467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551

見ての通り、コンテナに対して IP アドレスを指定できました。docker run コマンドでコンテナ作成時に、ユーザが接続先のサブネットを指定したら、任意の IPv4 アドレスと同時、あるいは別に IPv6 アドレスも指定できます。IPv4 の指定には -ip フラグを、あるいは IPv6 の指定には --ipv6 フラグを使います。また 、docker network connect コマンドでも追加できます。IP アドレスの指定は、コンテナのネットワーク設定の一部です。そのため、コンテナを再起動しても IP アドレスは維持されるでしょう。将来的にはユーザ定義ネットワーク上でのみ利用可能になります。ユーザ定義ネットワーク以外では、デーモンを再起動時にサブネット設定情報の維持を保証しないためです。

次は、 container3 に対するネットワークのリソースを調査します。

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  container3
{"isolated_nw":{"IPAMConfig":{"IPv4Address":"172.25.3.3"},"NetworkID":"1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
"EndpointID":"dffc7ec2915af58cc827d995e6ebdc897342be0420123277103c40ae35579103","Gateway":"172.25.0.1","IPAddress":"172.25.3.3","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:19:03:03"}}

このコマンドを container2 にも繰り返します。Python をインストール済みであれば、次のように表示を分かりやすくできるでしょう。

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  container2 | python -m json.tool
{
    "bridge": {
        "NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812",
        "EndpointID": "0099f9efb5a3727f6a554f176b1e96fca34cae773da68b3b6a26d046c12cb365",
        "Gateway": "172.17.0.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAMConfig": null,
        "IPAddress": "172.17.0.3",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "MacAddress": "02:42:ac:11:00:03"
    },
    "isolated_nw": {
        "NetworkID":"1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "EndpointID": "11cedac1810e864d6b1589d92da12af66203879ab89f4ccd8c8fdaa9b1c48b1d",
        "Gateway": "172.25.0.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAMConfig": null,
        "IPAddress": "172.25.0.2",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "MacAddress": "02:42:ac:19:00:02"
    }
}

container2 は2つのネットワークに所属しているのが分かります。 bridge ネットワークは起動時にデフォルトで参加したネットワークであり、 isolated_nw ネットワークは後から自分で接続したものです。

Docker のネットワーク

container3 の場合は、 docker runisolated_nw に接続しました、そのため、このコンテナは bridge に接続していません。

docker attach コマンドで実行中の container2 に接続し、ネットワーク・スタックを確認しましょう。

$ docker attach container2

コンテナのネットワーク・スタックを確認したら、2つのイーサネット・インターフェースが見えます。1つはデフォルトの bridge ネットワークであり、もう1つは isolated_nw ネットワークです。

/ # 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:8 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:648 (648.0 B)  TX bytes:648 (648.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:15:00:02
          inet addr:172.25.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe19:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 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:648 (648.0 B)  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)

isolated_nw はユーザが定義したネットワークであり、Docker 内部 DNS サーバがネットワーク上の他コンテナに対する適切な名前解決をします。 container2 の内部では、 container3 に対して名前で ping できるでしょう。

/ # ping -w 4 container3
PING container3 (172.25.3.3): 56 data bytes
64 bytes from 172.25.3.3: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.3.3: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.3.3: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.3.3: seq=3 ttl=64 time=0.097 ms

--- container3 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

ただし、デフォルトの bridge ネットワークを使う場合は、この名前解決機能を利用できません。 container2container1 は、どちらもデフォルトのブリッジ・ネットワークに接続しています。このデフォルトのネットワーク上では、Docker は自動サービス・ディスカバリをサポートしません。そのため、 container1 に対して名前で ping をしても、 /etc/hosts ファイルに記述しない限り失敗するでしょう。

/ # ping -w 4 container1
ping: bad address 'container1'

container1 の IP アドレスであれば、次のように処理できます。

/ # ping -w 4 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.095 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
64 bytes from 172.17.0.2: seq=3 ttl=64 time=0.101 ms

--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.072/0.085/0.101 ms

container1container2 を接続したい場合は、 docker run --link コマンドを使います。すると、2つのコンテナは IP アドレスだけでなく、名前でも相互に通信可能となります。

container2 からデタッチして離れるには、 CTRL-p CTRL-q を実行します。

この例では、 container2 は両方のネットワークに接続しているため、 container1container3 の両方と通信できます。しかし、 container3container1 は同じネットワーク上に存在していないため、お互いに通信できません。確認のため、 container3 にアタッチし、 container1 の IP アドレスに対して ping を試みましょう。

$ docker attach container3
/ # ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
^C
--- 172.17.0.2 ping statistics ---
10 packets transmitted, 0 packets received, 100% packet loss

コンテナをネットワークに接続するには、実行中でも停止中でも可能です。しかし、 docker network inspect が表示するのは、実行中のコンテナのみです。

ユーザ定義ネットワークでコンテナをリンク

先の例では、ユーザ定義ネットワーク isolated_nw において、 container2 は自動的に container3 の名前解決が可能でした。しかし、デフォルトの bridge ネットワークでは自動的に名前解決が行われません。そのため、後方互換性のある レガシーのリンク機能 を使い続ける必要が求められます。

レガシーのリンク は、デフォルト bridge ネットワーク上で4つの主な機能を提供します。

  • 名前解決
  • --link=コンテナ名:エイリアス の形式で、リンクしたコンテナの別名を指定
  • コンテナの接続性を安全にする( --icc=false で分離する )
  • 環境変数の挿入

上の4つの機能を、例で使ったデフォルトではない isolated_nw のようなユーザ定義ネットワークと比較します。 docker network では追加設定を行わないものとします。

  • DNS を使い自動的に名前解決
  • ネットワーク内のコンテナに対して、安全に隔離された環境を自動的に
  • 複数のネットワークを動的に装着・取り外しできる能力
  • リンクしているコンテナに対しては --link オプションでエイリアス名を指定

先ほどの例で説明を続けます。 isolated_nw に別のコンテナ container4 を作成しましょう。この時、 --link オプションを付ければ、同一ネットワーク上の他コンテナが名前解決に使える別名(エイリアス)を指定できます。

$ docker run --net=isolated_nw -itd --name=container4 --link container5:c5 busybox
01b5df970834b77a9eadbaff39051f237957bd35c4c56f11193e0594cfd5117c

--link の助けにより、 container4container5 に接続するために、 c5 という別名でも接続できます。

container4 の作成時、リンクしようとする container5 という名前のコンテナは、まだ作成していないに注意してください。これが、デフォルト bridge における レガシーのリンク 機能と、ユーザ定義ネットワークにおける新しい リンク 機能とで異なる挙動の1つです。 レガシーのリンク は静的(固定)です。コンテナに対するエイリアス名は固定であり、リンク対象のコンテナを再起動は許容されません。一方のユーザ定義ネットワークにおける新しい リンク 機能であれば、動的な性質を持っています。リンク対象のコンテナ再起動は許容されますし、IP アドレスの変更もできます。

それでは container4 を c4 としてリンクする container5 という名前の別コンテナを起動しましょう。

$ docker run --net=isolated_nw -itd --name=container5 --link container4:c4 busybox
72eccf2208336f31e9e33ba327734125af00d1e1d2657878e2ee8154fbb23c7a

予想通り、 container4container5 に対して接続できるのは、コンテナ名とエイリアス c5 の両方です。そして、 container5container4 に対しても、コンテナ名とエイリアスである c4 で接続できます。

$ docker attach container4
/ # ping -w 4 c5
PING c5 (172.25.0.5): 56 data bytes
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms

--- c5 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

/ # ping -w 4 container5
PING container5 (172.25.0.5): 56 data bytes
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms

--- container5 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms
$ docker attach container5
/ # ping -w 4 c4
PING c4 (172.25.0.4): 56 data bytes
64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms
64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms
64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms
64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms

--- c4 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.065/0.070/0.082 ms

/ # ping -w 4 container4
PING container4 (172.25.0.4): 56 data bytes
64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms
64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms
64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms
64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms

--- container4 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.065/0.070/0.082 ms

レガシーのリンク機能と新しいリンクのエイリアスは、コンテナに対してエイリアス名で接続するという意味では似ています。しかし、レガシーのリンクはコンテナに --link を指定した範囲でしか機能しません。

加えて、重要な注意点があります。コンテナが複数のネットワークに所属している場合、リンクのエイリアス(別名)が有効な範囲は、所属するネットワーク全体に適用されます。そのため、別のネットワークでは異なるエイリアスとしてリンクされる場合があります。

先ほどの例を進めます。 local_alias という別のネットワークを作成しましょう。

$ docker network create -d bridge --subnet 172.26.0.0/24 local_alias
76b7dc932e037589e6553f59f76008e5b76fa069638cd39776b890607f567aaa

container4container5 を新しい local_aliases ネットワークに接続します。

$ docker network connect --link container5:foo local_alias container4
$ docker network connect --link container4:bar local_alias conta
$ docker attach container4

/ # ping -w 4 foo
PING foo (172.26.0.3): 56 data bytes
64 bytes from 172.26.0.3: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.26.0.3: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.26.0.3: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.26.0.3: seq=3 ttl=64 time=0.097 ms

--- foo ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

/ # ping -w 4 c5
PING c5 (172.25.0.5): 56 data bytes
64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms

--- c5 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

異なったネットワーク上でも ping が成功するのに注目してください。このセクションの結論を導くために、 container5isolated_nw から切り離し、その結果を観察しましょう。

$ docker network disconnect isolated_nw container5

$ docker attach container4

/ # ping -w 4 c5
ping: bad address 'c5'

/ # ping -w 4 foo
PING foo (172.26.0.3): 56 data bytes
64 bytes from 172.26.0.3: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.26.0.3: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.26.0.3: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.26.0.3: seq=3 ttl=64 time=0.097 ms

--- foo ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

結論として、ユーザ定義ネットワークにおける新しいリンク機能は、 従来のリンク機能が抱えていた問題を解決しているため、あらゆる面で レガシーのリンク より優位と言えます。

レガシーのリンク 機能と比較する場合、失われた機能の1つとして環境変数の挿入を注目すべきです。環境変数の挿入は非常に便利なものです。しかし、静的な性質であり、コンテナが開始する時に必ず挿入する必要がありました。環境変数を挿入できなかったのは、 docker network との互換性を保つためです。これはネットワークにコンテナを動的に接続/切断する手法であり、環境変数の挿入は、実行中のコンテナに対して影響を与えてしまうからです。

ネットワーク範囲のエイリアス

リンク 機能はコンテナ内におけるプライベートな名前解決を提供します。ネットワーク範囲のエイリアス(network-scoped alias)とは、特定のネットワークの範囲内でコンテナのエイリアス名を有効にします。

先ほどの例を続けます。 isolated_nw でネットワーク・エイリアスを有効にした別のコンテナを起動します。

$ docker run --net=isolated_nw -itd --name=container6 --net-alias app busybox
8ebe6767c1e0361f27433090060b33200aac054a68476c3be87ef4005eb1df17
$ docker attach container4
/ # ping -w 4 app
PING app (172.25.0.6): 56 data bytes
64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms

--- app ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

/ # ping -w 4 container6
PING container5 (172.25.0.6): 56 data bytes
64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms

--- container6 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

container6local_alias ネットワークに接続しますが、異なったネットワーク範囲エイリアスを指定します。

$ docker network connect --alias scoped-app local_alias container6

この例における container6 は、 isolated_nw では app とエイリアス名が指定されており、 local_alias では scoped-app とエイリアス名が指定されています。

container4 (両方のネットワークに接続)と container5isolated_nw のみ接続 )から接続できるか確認しましょう。

$ docker attach container4

/ # ping -w 4 scoped-app
PING foo (172.26.0.5): 56 data bytes
64 bytes from 172.26.0.5: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.26.0.5: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.26.0.5: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.26.0.5: seq=3 ttl=64 time=0.097 ms

--- foo ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

$ docker attach container5

/ # ping -w 4 scoped-app
ping: bad address 'scoped-app'

ご覧の通り、ネットワーク範囲のエイリアスとは、ネットワークをエイリアスとしてアクセス可能に定義した範囲内のコンテナのみです。

この機能に加え、同一ネットワーク内であれば、複数のコンテナが同じネットワーク範囲としてのエイリアス名を共有できます。例えば isolated_nwcontainer7container6 と同じエイリアスで起動しましょう。

$ docker run --net=isolated_nw -itd --name=container7 --net-alias app busybox
3138c678c123b8799f4c7cc6a0cecc595acbdfa8bf81f621834103cd4f504554

複数のコンテナが同じエイリアス名を共有する時、エイリアスの名前解決はコンテナのいずれかで行います(通常は初めてエイリアス指定をしたコンテナです)。コンテナが停止してエイリアスが無効になるか、ネットワークから切断すれば、次のコンテナが名前解決のエイリアスに使われます。

container4 から app エイリアスに ping をした後、 container6 を停止します。その後、 app に対する名前解決が container7 になるのを確認しましょう。

$ docker attach container4
/ # ping -w 4 app
PING app (172.25.0.6): 56 data bytes
64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms

--- app ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

$ docker stop container6

$ docker attach container4
/ # ping -w 4 app
PING app (172.25.0.7): 56 data bytes
64 bytes from 172.25.0.7: seq=0 ttl=64 time=0.095 ms
64 bytes from 172.25.0.7: seq=1 ttl=64 time=0.075 ms
64 bytes from 172.25.0.7: seq=2 ttl=64 time=0.072 ms
64 bytes from 172.25.0.7: seq=3 ttl=64 time=0.101 ms

--- app ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.072/0.085/0.101 ms

コンテナの切断

コンテナをネットワークから切断するには docker network disconnect コマンドを使います。

$ docker network disconnect isolated_nw container2

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  container2 | python -m json.tool
{
    "bridge": {
        "EndpointID": "9e4575f7f61c0f9d69317b7a4b92eefc133347836dd83ef65deffa16b9985dc0",
        "Gateway": "172.17.0.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAddress": "172.17.0.3",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "MacAddress": "02:42:ac:11:00:03"
    }
}


$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.21.0.0/16",
                    "Gateway": "172.21.0.1/16"
                }
            ]
        },
        "Containers": {
            "467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551": {
                "Name": "container3",
                "EndpointID": "dffc7ec2915af58cc827d995e6ebdc897342be0420123277103c40ae35579103",
                "MacAddress": "02:42:ac:19:03:03",
                "IPv4Address": "172.25.3.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]

コンテナがネットワークから切断したら、対象ネットワーク上で接続していたコンテナと通信できなくなります。この例では、 container2isolated_nw ネットワーク上の container3 とは通信できなくなります。

$ 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:8 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:648 (648.0 B)  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)

/ # ping container3
PING container3 (172.25.3.3): 56 data bytes
^C
--- container3 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

container2 は、ブリッジ・ネットワークに対する接続性をまだ維持しています。

/ # ping container1
PING container1 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.119 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.174 ms
^C
--- container1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.119/0.146/0.174 ms
/ #

複数ホストのネットワークにおいて、不意に docker デーモンの再起動が発生するシナリオを考えます。デーモンは接続していたエンドポイントとの接続性を解消していないものとします。エンドポイントでは、新しいコンテナがかつてと同じ名前で接続しようとしても container already connected to network (コンテナは既にネットワークに接続している)とエラーが出るかもしれません。エンドポイントの認識が古いのを解消するには、まず最初にコンテナを削除し、エンドポイントのネットワークから強制的に切断します( docker network disconnect -f )。エンドポイントがクリーンアップされれば、コンテナはネットワークに接続できるようになります。

$ docker run -d --name redis_db --net multihost redis
ERROR: Cannot start container bc0b19c089978f7845633027aa3435624ca3d12dd4f4f764b61eac4c0610f32e: container already connected to network multihost

$ docker rm -f redis_db
$ docker network disconnect -f multihost redis_db

$ docker run -d --name redis_db --net multihost redis
7d986da974aeea5e9f7aca7e510bdb216d58682faa83a9040c2f2adc0544795a

ネットワークの削除

ネットワーク上の全てのコンテナが停止するか切断したら、ネットワークを削除できます。

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

$ docker network rm isolated_nw

全てのネットワーク情報を確認したら、 isolated_nw が削除されています。

$ docker network ls
NETWORK ID          NAME                DRIVER
72314fa53006        host                host
f7ab26d71dbd        bridge              bridge
0f32e83e61ac        none                null