レガシーのコンテナ・リンク機能¶
このセクションで説明する過去(レガシー)のコンテナ・リンク機能に関する情報は、Docker のデフォルト・ブリッジ内でのみ扱えます。デフォルト・ブリッジとは bridge
という名称の ブリッジ
ネットワークであり、Docker をインストールすると自動的に作成されます。
Docker にネットワーク機能 を導入するまでは、この Docker リンク機能によって、あるコンテナから別のコンテナに対してコンテナ間で相互の発見をし、安全に転送する情報を得られました。これから Docker ネットワーク機能を学ぶのであれば注意点があります。今もリンク機能を使いコンテナを作成できます。ただし、デフォルトの ブリッジ
ネットワークと ユーザ定義ネットワーク では、サポートされている機能が異なるのでご注意ください。
このセクションではネットワーク・ポートの接続と、それらをデフォルトの bridge
ネットワーク上のコンテナ上でリンクする方法を簡単に扱います。
ネットワークのポート・マッピングで接続¶
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
次は、 db
コンテナにリンクする新しい web
コンテナを作成します。。
$ docker run -d -P --name web --link db:db training/webapp python app.py
これは先ほど作成した db
コンテナを新しい web
コンテナにリンクするものです。 --link
フラグは次のような形式です。
--link <名前 or id>:エイリアス
名前
の場所はリンクしようとしているコンテナ名の場所であり、 エイリアス
はリンク名の別名です。 --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.82
prefix_PORT
変数は、URL 用のポート番号を含む。例:WEBDB_PORT_5432_TCP_PORT=5432
prefix_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 は環境変数を作成しており、そこには元になった ソース
コンテナに関する便利な情報を含みます。各変数にある接頭語 DB_
とは、先ほど指定した エイリアス
から割り当てられています。もし 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つのエントリが見えます。1行めエントリは、 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
参考
- Legacy container links
- https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/