過去のコンテナ・リンク機能¶
このセクションで説明する情報は、Docker のデフォルト・ブリッジ内で扱える、過去のコンテナ・リンク機能に関してです。これは bridge
という名称の bridge
ネットワークであり、Docker をインストールすると自動的に作成されます。
Docker ネットワーク機能 が導入されるよりも前は、この Docker リンク機能によって、あるコンテナから別のコンテナに対してコンテナ間で相互の発見をし、安全に転送する情報を得られました。Docker ネットワーク機能について学んでいく前に、まだリンク機能を作成することはできますが、サポートされている機能は、デフォルトの bridge
ネットワークと ユーザ定義ネットワーク では異なるのでご注意ください。
このセクションではネットワーク・ポートの接続と、それらをデフォルトの 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
次は、新しい 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.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 は環境変数を作成しており、そこには元になった 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
参考
- Legacy container links
- https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/