レガシーのコンテナ・リンク機能¶
警告
--link フラグは Docker のレガシー機能です。最終的に削除される可能性があります。絶対に使い続ける必要がない限り、2つのコンテナ間の通信に --link を使うのではなく、ユーザ定義ネットワークの使用を推奨します。ユーザ定義ネットワークでは --links の指定によるコンテナ間の環境変数をサポートしません。しかしながら、ボリュームのような、コンテナ間で制御しやすい仕組みが利用できるようになります。
--link の使用に代わる方法は ユーザ定義ブリッジとデフォルト・ブリッジとの違い をご覧ください。
このセクションで説明する過去(レガシー)のコンテナ・リンク機能に関する情報は、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 ポートと SCTP (典型的に SIGTRAN、Diameter、S1AP/X2AP といった通信プロトコルで使用する)ポートを割り当てたい場合は、最後に /udp や /sctp を追加します。例えば、次のように実行します。
$ 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.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 は環境変数を作成しており、そこには元になった ソース コンテナに関する便利な情報を含みます。各変数にある接頭語 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/