過去のコンテナ・リンク機能¶
このセクションで説明する情報は、Docker のデフォルト・ブリッジ内で扱える、過去のコンテナ・リンク機能に関してです。これは bridge という名称の bridge ネットワークであり、Docker をインストールすると自動的に作成されます。
Docker ネットワーク機能 の前に、Docker リンク機能によって、あるコンテナから別のコンテナに対してコンテナ間で相互の発見をし、安全に転送する情報を得られます。Docker ネットワーク機能について学んでいく前に、まだリンク機能を作成することはできますが、サポートされているのは bridge という名前の bridge ネットワーク上(ネットワーク・スタック上の docker0 )のみです。
このセクションではネットワーク・ポートの接続と、それらをコンテナ上でリンクする方法を簡単に扱います。リンクはまだ Docker のデフォルト・ネットワーク( bridge bridge )でサポートされていますが、Docker のネットワーク機能の選択としては、避けるべきでしょう。リンク機能は将来のリリースでは、廃止・削除される可能性があります。
ネットワークのポート割り当てを使い接続¶
Docker を使う のセクションでは、Python Flask アプリケーションを動かすコンテナを、次のように作成しました。
$ docker run -d -P training/webapp python app.py
注釈
コンテナは内部ネットワークと IP アドレスを持っています( Docker を使う セクションで、docker inspect コマンドを実行してコンテナの IP アドレスを確認しました )。Docker は様々なネットワーク設定を持っています。Docker ネットワーク機能の詳細は こちら をご覧ください。
コンテナを作成するとき -P フラグを使うと、自動的にコンテナ内部のネットワーク・ポートが、Docker ホスト上のエフェメラル・ポート範囲内にあるランダムなハイポートに割り当てられます。次は docker ps を実行時、コンテナ内のポート 5000 が、ホスト側の 49115 に接続されているのが分かります。
$ docker ps nostalgic_morse
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
また、コンテナのポートを特定のポートに割り当てるには、 -p フラグを使う方法もみてきました。ここでは、ホスト側のポート 80 に、コンテナのポート 5000 を割り当て(マップ)しています。
$ docker run -d -p 80:5000 training/webapp python app.py
そしてこの方法は、なぜ良い考えではないのか。それは、特定のコンテナが特定のポートを拘束するため、ということも分かりました。
その代わり、コンテナがポートを割り当てるにあたり、デフォルトのエフェメラル・ポート範囲内を使うよりも、自分でホスト側のポート範囲を指定した方が望ましいでしょう。
$ docker run -d -p 8000-9000:5000 training/webapp python app.py
これはコンテナのポート 5000 を、ホスト側のポート 8000 ~ 9000 の範囲で利用可能なポートをランダムに割り当てます。
また、 -p フラグは他の目的のためにも設定できます。デフォルトの -p フラグは、ホスト側マシンの全てのインターフェースに対する特定のポートを使用します。ですが、特定のインターフェースの使用を明示することが可能です。例えば、 localhost のみ指定するには、次のようにします。
$ docker run -d -p 127.0.0.1:80:5000 training/webapp python app.py
これはコンテナ内のポート 5000 を、ホスト側マシン上の localhost か 127.0.0.1 インターフェース上のポート 80 に割り当てます。
あるいは、コンテナ内のポート 5000 を使用して、ホスト側に動的に割り当てられますが、 localhost だけ使いたい時は、次のようにします。
$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py
また、UDP ポートを割り当てたい場合は、最後に /udp を追加します。例えば、次のように実行します。
$ docker run -d -p 127.0.0.1:80:5000/udp training/webapp python app.py
また、便利な docker port ショートカットについても学びました。これは現在ポートが割り当てられている情報も含みます。これは、特定のポートに対する設定を確認するのにも便利です。例えば、ホストマシン上の localhost にコンテナのポートを割り当てている場合、 docker port を実行すると次のような出力が返ります。
$ docker port nostalgic_morse 5000
127.0.0.1:49155
注釈
複数のポートを設定する場合は、-p フラグを複数回使えます。
リンクしているシステムに接続¶
Docker コンテナが他のコンテナに接続する方法は、ネットワーク・ポートの割り当て(mapping)だけではありません。Docker はリンク・システム(linking system)もあります。これは、複数のコンテナを一緒にリンクするもので、あるコンテナから別のコンテナに対する接続情報を送信します。コンテナがリンクされると、ソース・コンテナに関する情報が、受信者側のコンテナに送られます。これにより、受信者側は送信元のコンテナを示す説明データを選ぶことができます。
名前付けの重要さ¶
リンクを有効化すると、Docker はコンテナ名に依存するようになります。既に見てきたように、各コンテナを作成すると自動的に名前が作成されます。実際、このガイドでは nostalgic_morse という古い友人のような名前でした。コンテナ名は自分自身でも名付けられます。この名付けは2つの便利な機能を提供します。
- コンテナに名前を付けるのは、コンテナの名前を覚えておくためなど、特定の役割には便利です。たとえば、ウェブ・アプリケーションのコンテナには
webと名付けます。
- Docker で他のコンテナが参照できるようにするための、リファレンス・ポイント(参照地点)を提供します。例えば、
webコンテナをdbコンテナへリンクします。
コンテナ名を指定するには --name フラグを使います。例:
$ docker run -d -P --name web training/webapp python app.py
これは新しいコンテナを起動し、 --name フラグでコンテナ名を web とします。コンテナ名は 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 を使い、表示結果からコンテナ名の確認もできます。
注釈
コンテナ名はユニーク(一意)である必要があります。つまり、 web と呼べるコンテナは1つだけです。コンテナ名を再利用したい場合は、同じ名前で新しいコンテナを作成する前に、古いコンテナを削除( docker rm を使用 )する必要があります。あるいは別の方法として、 docker run コマンドの実行時に --rm フラグを指定します。これは、コンテナが停止したら、ただちにコンテナを削除するオプションです。
リンクを横断する通信¶
コンテナに対するリンクによりお互いのことを発見(discover)し、あるコンテナから別のコンテナに対して安全に転送する情報を得られます。リンクをセットアップすると、送信元コンテナから送信先コンテナに対する導線を作成します。リンクを作成するには、 --link フラグを使います。まず、新しいコンテナを作成します。今回はデータベースを含むコンテナを作成します。
$ docker run -d --name db training/postgres
これは PostgreSQL データベースが含まれる training/postgres イメージから db という名称のコンテナを作成します。
次は、先ほどの手順で web コンテナを既に作成しているのであれば、リンクできるようにするものへ置き換えるため、削除する必要があります。
$ docker rm -f web
次は、新しい web コンテナを作成し、 db コンテナにリンクします。
$ docker run -d -P --name web --link db:db training/webapp python app.py
これは先ほど作成した db コンテナを新しい web コンテナにリンクするものです。 --link フラグは次のような形式です。
--link <名前 or id>:alias
name の場所はリンク使用としているコンテナ名の場所であり、 alias はリンク名の別名です。 --link フラグも、次のような形式です。
--link <名前 or id>
このケースではエイリアスはコンテナ名と一致しています。先ほどの例は、次のようにも書き換えられます。
$ docker run -d -P --name web --link db training/webapp python app.py
次は、 docker inspect でリンクされたコンテナを確認しましょう。
$ docker inspect -f "{{ .HostConfig.Links }}" web
[/db:/web/db]
これで web コンテナは db コンテナに web/db としてリンクされました。これを使い、 db コンテナに対する接続情報を得られます。
コンテナに対するリンクとは、実際には何をしているのでしょうか? これまで学んだように、リンクとは、送信元コンテナが送信先コンテナに送るため、自分自身の情報を提供します。今回の例では、受信者は web であり、ソース・ db に関する接続情報を入手できます。これにより、Docker はコンテナ間で安全なトンネルを作成します。つまり、 db コンテナを開始する時に、 -P や -p フラグを使えないことに注意してください。これはリンク機能の大きな利点です。これは、元のコンテナのポートを公開する必要がありません。ここでは PostgreSQL データベースをネットワークに接続する必要がありません。
Docker が元コンテナから送信先コンテナに接続情報を渡すには、2つの方法があります。
- 環境変数
/etc/hostsファイルの更新
環境変数¶
Docker はリンクするコンテナに対する様々な環境変数を作成します。Docker は --link パラメータで指定したコンテナをターゲットとする環境変数を、自動的に作成します。また、Docker が参照元とするコンテナの環境変数も作成します。これらの環境変数を使うには、次のようにします。
- ソース・コンテナの Dockerfile で
ENVコマンドを使う。 - ソース・コンテナの開始時に、
docker runコマンドで-e、--env、--env-fileオプションを使う。
これらの環境変数は、ディスカバリのプログラム化を実現します。これはターゲットのコンテナ内の情報に、ソース・コンテナに関連する情報が含まれます。
警告
重要な理解が必要なのは、Docker がコンテナに関して作成する 全て の環境変数が、リンクされた あらゆる コンテナで利用できることです。これにより、機密事項を扱うデータをコンテナに保管する場合は、セキュリティに関する重大な影響を及ぼす場合があります。
Docker は --list パラメータで指定したターゲットコンテナごとに <エイリアス>_名前 環境変数を作成します。たとえば、新しいコンテナ web がデータベース・コンテナ db とリンクするのに `--link db:webdb` を指定します。それから Docker は ``web コンテナ内で WEBDB_NAME=/web/webdb 環境変数を作成します。
また Docker は、ソース・コンテナが公開している各ポートの環境変数も定義します。各変数には、ユニークな接頭語を付けています。
<名前>_PORT_<ポート番号>_<プロトコル>
この接頭語の要素は、次の通りです。
- エイリアスの
<名前>を--linkパラメータで指定している場合(例:webdb) - 公開している
<ポート>番号 - TCP もしくは UDP の
<プロトコル>
Docker はこれら接頭語の形式を、3つの異なる環境変数で使います。
prefix_ADDR変数は、URL 用の IP アドレスを含む。例:WEBDB_PORT_5432_TCP_ADDR=172.17.0.82prefix_PORT変数は、URL 用のポート番号を含む。例:WEBDB_PORT_5432_TCP_PORT=5432prefix_PROTO変数は URL 用のプロトコルを含む。例:WEBDB_PORT_5432_TCP_PROTO=tcp
もしコンテナが複数のポートを公開している場合は、それぞれのポートを定義する環境変数が作成されます。つまり、例えばコンテナが4つのポートを公開しているのであれば、Docker は各ポートごとに3つの環境変数を作成するので、合計12個の変数を作成します。
さらに、Docker は <エイリアス>_ポート の環境変数も作成します。この変数にはソース・コンテナが1番目に公開しているポートの URL を含みます。「1番目」のポートとは、公開されているポートのうち、最も低い番号です。例えば、 WEBDB_PORT=tcp://172.17.0.82:5432 のような変数が考えられます。もし、ポートが tcp と udp の両方を使っているのであれば、tcp のポートだけが指定されます。
最後に、ソース・コンテナ上の Docker に由来する環境変数は、ターゲット上でも環境変数として使えるように公開されます。Docker が作成した各環境変数 <エイリアス>_ENV_<名前> が、ターゲットのコンテナから参照できます。これら環境変数の値は、ソース・コンテナが起動したときのものが使われます。
データベースの例に戻りましょう。 env コマンドを実行すると、指定したコンテナの環境変数一覧が表示されます。
$ docker run --rm --name web2 --link db:db training/webapp env
. . .
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
DB_PORT_5432_TCP_PROTO=tcp
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_ADDR=172.17.0.5
. . .
このように、Docker は環境変数を作成しており、そこには元になった source コンテナに関する便利な情報が含まれています。各変数にある接頭語 DB_ とは、先ほど指定した alias から割り当てられています。もし alias が db1 であれば、環境変数の接頭語は DB1_ になります。これらの環境変数を使い、アプリケーションが db コンテナ上のデターベースに接続する設定も可能です。接続は安全かつプライベートなものですが、これはリンクされた web コンテナと db コンテナが通信できるようにするだけです。
Docker 環境変数に関する重要な注意¶
/etc/hosts ファイル のエントリとは違い、もし元になったコンテナが再起動しても、保管されている IP アドレスの情報は自動的に更新されません。リンクするコンテナの IP アドレスを名前解決するには、 /etc/hosts エントリの利用をお勧めします。
これらの環境変数が作成されるのは、コンテナの初期段階のみです。 sshd のようなデーモンであれば、シェルへの接続が生じたときに確定します。
/etc/hosts ファイルの更新¶
環境変数について付け加えておくと、 Docker は /etc/hosts ファイルに、元になったコンテナのエントリを追加します。ここでは web コンテナのエントリを見てみましょう。
$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7 aed84ee21bde
. . .
172.17.0.5 webdb 6e5cdeb2d300 db
関係あるホスト2つのエントリが見えます。はじめのエントリは、 web コンテナのものであり、コンテナ ID がホスト名として使われています。2つめのエントリは db コンテナのものであり、IP アドレスの参照にエイリアスが使われています。エイリアスの指定に加えて、もし --link パラメータで指定したエイリアスがユニークであれば、リンクされるコンテナのホスト名もまた /etc/hosts でコンテナの IP アドレスがリンクされます。これでホスト上では、これらのエントリを通して ping できます。
root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping webdb
PING webdb (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms
注釈
この例で ping をインストールしているのは、コンテナの初期状態では入っていないためです。
これで、 db コンテナに対して ping コマンドを実行するときは、 hosts エントリにある 172.17.0.5 を名前解決して ping します。この hosts のエントリの設定を使えば、アプリケーションが db コンテナへ接続する設定に使えます。
注釈
1つのソース・コンテナから、複数の送信先コンテナにリンクできます。例えば、複数の(異なった名前の)ウェブ・コンテナが、 db コンテナに接続できます。
ソース・コンテナを再起動すると、リンクされたコンテナの /etc/hosts ファイルはソース・コンテナの IP アドレスを自動的に更新し、継続して通信できるようにします。
$ docker restart db
db
$ docker run -t -i --rm --link db:db training/webapp /bin/bash
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7 aed84ee21bde
. . .
172.17.0.9 db