コンテナのネットワーク

これまでのユーザ・ガイドでは、単純なアプリケーションを構築して実行しました。また、自分でイメージの構築をしました。このセクションでは、コンテナをどのように接続するかを学びます。

コンテナ名

これまで作成してきたコンテナは、自動的にコンテナ名が作成されました。このガイドでは nostalgic_morse という古い友人のような名前でした。自動ではなく、自分でもコンテナに名前を付けられます。コンテナに名前があれば、2つの便利な機能が使えます。

  • コンテナに対して何らかの役割を示す名前を付けると、簡単に覚えられます。例えば、ウェブ・アプリケーションを含むコンテナには web と名付けます。
  • 名前を付けると、それが Docker の他コンテナから参照する時のポイントになります。後ほど、この働きをサポートする複数のコマンドを紹介します。

コンテナに名前を付けるには、--name フラグを使います。例えば、新しく起動するコンテナを web と呼ぶには、次のように実行します。

$ docker run -d -P --name web training/webapp python app.py

docker ps コマンドで名前を確認します。

$ docker ps -l
CONTAINER ID  IMAGE                  COMMAND        CREATED       STATUS       PORTS                    NAMES
aed84ee21bde  training/webapp:latest python app.py  12 hours ago  Up 2 seconds 0.0.0.0:49154->5000/tcp  web

あるいは docker inspect を使ってもコンテナ名を確認できます。

$ docker inspect web
[
{
    "Id": "3ce51710b34f5d6da95e0a340d32aa2e6cf64857fb8cdb2a6c38f7c56f448143",
    "Created": "2015-10-25T22:44:17.854367116Z",
    "Path": "python",
    "Args": [
        "app.py"
    ],
    "State": {
        "Status": "running",
        "Running": true,
        "Paused": false,
        "Restarting": false,
        "OOMKilled": false,
  ...

コンテナ名はユニークである必要があります。これが意味するのは、web と呼ばれるコンテナはただ一つしか使えません。もしも同じコンテナ名を再利用したいならば、新しいコンテナで名前を使う前に、古いコンテナを削除(docker rm コマンドで)しなくてはいけません。web コンテナの停止と削除をしてから、次に進みます。

$ docker stop web
web
$ docker rm web
web

コンテナをデフォルトのネットワークで起動

Docker は ネットワーク・ドライバ を使うことで、コンテナのネットワーク(訳者注:連結や接続するという意味の機能)をサポートします。標準では、Docker は bridge (ブリッジ) と overlay (オーバレイ) の2つのネットワーク・ドライバを提供します。高度な使い方として、自分でネットワーク・ドライバ・プラグインを書き、その自分のドライバでネットワークを作成することも可能です。

Docker Engine は、自動的に3つのデフォルト・ネットワークをインストールします。

$ docker network ls
NETWORK ID          NAME                DRIVER
18a2866682b8        none                null
c288470c46f6        host                host
7b369448dccb        bridge              bridge

bridge という名前のネットワークは特別です。特に指定しなければ、Docker は常にこのネットワーク上にコンテナを起動します。次のコマンドを試します:

$ docker run -itd --name=networktest ubuntu
74695c9cea6d9810718fddadc01a727a5dd3ce6a69d09752239736c030599741

ネットワークの調査(訳者注: network inspect コマンド)によって、コンテナの IP アドレスが簡単に分かります。

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

コンテナを切断(disconnect)し、ネットワークからコンテナを取り外せます。切断にはネットワーク名とコンテナ名を指定します。あるいは、コンテナ ID も使えます。この例では、名前を指定する方が速いです。

$ docker network disconnect bridge networktest

コンテナをネットワークから切断しようとしても、 bridge という名前で組み込まれている ブリッジ ネットワークを削除できません。ネットワークとはコンテナを他のコンテナやネットワークを隔離する一般的な手法です。そのため、Docker を使い込み、自分自身でネットワークの作成も可能です。

ブリッジ・ネットワークの作成

Docker Engine はブリッジ・ネットワークとオーバレイ・ネットワークをどちらもネイティブにサポートしています。ブリッジ・ネットワークは、単一ホスト上で実行している Docker Engine でしか使えない制限があります。オーバレイ・ネットワークは複数のホストで導入でき、高度な使い方ができます。次の例は、ブリッジ・ネットワークの作成です。

$ docker network create -d bridge my-bridge-network

Docker に対して新しいネットワークで使用する bridge ドライバを指定するには、 -d フラグを使います。このフラグを指定しなくても、同様にこの bridge フラグが適用されます。マシン上のネットワーク一覧を表示します。

$ docker network ls
NETWORK ID          NAME                DRIVER
7b369448dccb        bridge              bridge
615d565d498c        my-bridge-network   bridge
18a2866682b8        none                null
c288470c46f6        host                host

このネットワークを調査しても、中にはコンテナが存在しないのが分かります。

$ docker network inspect my-bridge-network
[
    {
        "Name": "my-bridge-network",
        "Id": "5a8afc6364bccb199540e133e63adb76a557906dd9ff82b94183fc48c40857ac",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

ネットワークにコンテナを追加

ウェブ・アプリケーションの構築にあたり、安全性を高めるためにネットワークを作成します。ネットワークとは、コンテナの完全な分離を提供するものと定義します。コンテナを実行する時に、コンテナをネットワークに追加できます。

PostgreSQL データベースを実行するコンテナを起動します。--net=my-bridge-network フラグを付けて、新しいネットワークに接続します。

$ docker run -d --net=my-bridge-network --name db training/postgres

my-bridge-network を調べると、コンテナがアタッチ(接続)しているのが分かります。同様にコンテナを調べても、どこに接続しているのか分かります。

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  db
{"my-bridge-network":{"NetworkID":"7d86d31b1478e7cca9ebed7e73aa0fdeec46c5ca29497431d3007d2d9e15ed99","EndpointID":"508b170d56b2ac9e4ef86694b0a76a22dd3df1983404f7321da5649645bf7043","Gateway":"172.18.0.1","IPAddress":"172.18.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}

次に進み、近くでウェブ・アプリケーションを起動します。今回は -P フラグもネットワークも指定しません。

$ docker run -d --name web training/webapp python app.py

ウェブ・アプリケーションはどのネットワーク上で実行しているのでしょうか。アプリケーションを調査したら、標準の bridge ネットワークで実行していることが分かります。

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  web
{"bridge":{"NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812","EndpointID":"508b170d56b2ac9e4ef86694b0a76a22dd3df1983404f7321da5649645bf7043","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}

次に web の IP アドレスを取得しましょう。

$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
172.17.0.2

次は、実行中の db コンテナでシェルを開きます:

$ docker exec -it db bash
root@a205f0dd33b2:/# ping 172.17.0.2
ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
^C
--- 172.17.0.2 ping statistics ---
44 packets transmitted, 0 received, 100% packet loss, time 43185ms

少したってから CTRL-C を使って ping を終了します。ping が通らないことが分かりました。これは、2つのコンテナが異なるネットワークで実行しているからです。これを修正しましょう。次に exit を使って、コンテナから出ます。

Docker のネットワーク機能は、必要に応じてコンテナに対して多くのネットワークを接続(attach)できます。接続は、実行中のコンテナに対しても可能です。次に、実行中の web アプリケーションを my-bridge-network に接続します。

$ docker network connect my-bridge-network web

db アプリケーションのシェルを再び開き、ping コマンドを再度試します。今回は IP アドレスではなく、コンテナ名 web を使います。

$ docker exec -it db bash
root@a205f0dd33b2:/# ping web
PING web (172.19.0.3) 56(84) bytes of data.
64 bytes from web (172.19.0.3): icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from web (172.19.0.3): icmp_seq=2 ttl=64 time=0.060 ms
64 bytes from web (172.19.0.3): icmp_seq=3 ttl=64 time=0.066 ms
^C
--- web ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.060/0.073/0.095/0.018 ms

別の IP アドレスに ping しているのが分かります。このアドレスは my-bridge-network のアドレスであり、 bridge ネットワーク上のものではありません。

次のステップ

コンテナのネットワークについて学びましたので、次は コンテナにおけるデータ管理 を理解していきます。