コンテナ・リンク機能(古い機能)¶
ここでは古い機能であるコンテナ・リンクについて説明します。
これは Docker のデフォルトである bridge ネットワーク内にあるもので、この bridge ネットワークは Docker をインストールした際に自動的に生成されます。
Docker のネットワーク機能 が提供される以前は、Docker のリンク機能によって複数のコンテナが互いを検出し、一方から他方への情報送信を安全に行うようにしていました。
Docker のネットワーク機能が導入されてからも、リンクを生成することはできます。
ただしデフォルトの bridge ネットワークであるか、ユーザ定義のネットワーク であるかによって、その動作は異なることになります。
この節においてはネットワークポートを通じてネットワークに接続する方法を簡単に説明した上で、デフォルトの bridge ネットワーク内でのコンテナ・リンクを行う方法へ進んでいきます。
警告
Docker の --link フラグは過去の機能です。
そのうちに削除されるかもしれません。
この機能を確実に必要としているのでなければ --link を使わず、2 つのコンテナ間の通信を実現するユーザ定義のネットワークを利用することをお勧めします。
--link に存在していて、ユーザ定義のネットワークにない機能は、コンテナ間で環境変数を共有できる機能です。
ただしボリュームのような別の機能を使えば、コンテナ間での環境変数の共有は、より制御しやすく利用できます。
ネットワーク・ポート・マッピングを利用した接続¶
以下のコマンドによって Python Flask アプリケーションを起動しているとします。
$ docker run -d -P training/webapp python app.py
注釈
コンテナには内部ネットワークと IP アドレスがあります。 そして Docker にはさまざまなネットワーク設定方法があります。 Docker のネットワーク機能の詳細は こちら を参照してください。
このコンテナの生成時には -P フラグが指定されているので、コンテナ内部のネットワークポートはすべて、Docker ホスト上の「エフェメラルポート」範囲内にあるランダムな高位ポートに自動的に割り当てられます。
その後に docker ps を実行すれば、コンテナ内の 5000 番ポートが、ホスト上の 49155 番ポートに割り当てられているのがわかります。
$ 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 フラグは、ホストマシン上のすべてのインターフェースに対して、指定されたポートを割り当てます。
しかし特定のインターフェースに対しての割り当てを行うこともできます。
たとえば以下は loalhost にのみ割り当てる例です。
$ docker run -d -p 127.0.0.1:80:5000 training/webapp python app.py
上はコンテナ内の 5000 番ポートを、ホストマシン上の 80 番ポートに割り当てますが、これが行われるのは localhost つまり 127.0.0.1 インターフェースに対してのみです。
コンテナ内の 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 フラグは複数個の指定が可能であり、これにより複数ポートの指定を行うことができます。
リンク・システムを用いた接続¶
注釈
この節ではデフォルトの bridge ネットワーク内の古い機能であるリンク機能について説明します。
ユーザ定義ネットワーク上のリンクに関しては ユーザ定義ネットワークでのコンテナのリンク を参照してください。
Docker コンテナを別のコンテナと接続させるのは、ネットワークのポート割り当てだけが唯一の方法ではありません。 Docker にはリンクシステム(linking system)があります。 このシステムにより複数のコンテナは互いにリンクすることが可能となり、接続情報をやり取りできるようになります。 複数のコンテナがリンクされていると、1 つのコンテナの情報を別のコンテナに送信することが可能です。 つまり情報を受け取る側のコンテナは、情報元のコンテナに関する情報の中から、必要な情報を取り出して見ることができます。
名前づけの重要性¶
Docker がリンクを確立するためには、コンテナの名前が重要になります。
これまでコンテナを生成した際には、各コンテナに自動的に名前がつけられることを見てきました。
実際にここまでの説明においては、おなじみの nostalgic_morse という名前を用いています。
コンテナの名前は自由につけることができます。
名前をつけることによって、以下の 2 点が得られます。
コンテナが実現する特定の機能に合わせて、それを表わす名称にしておくと覚えやすく便利です。 たとえばウェブ・アプリケーションを含んだコンテナには
webという名前をつけます。
名前は、他のコンテナから参照させるための参照名となります。 たとえば
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 container rm を使って)削除する必要があります。
その後であれば、同一名のコンテナを生成して利用することができます。
これとは別に docker run の --rm フラグを利用する方法もあります。
この方法ではそれまでのコンテナが停止され、すぐに削除されます。
リンク間の通信¶
リンク機能によって複数のコンテナが互いを検出し、一方から他方への情報送信を安全に行うことができます。 リンク機能を設定すると、情報発信元のコンテナと受信先のコンテナの間に経路が生成されます。 そして受信先コンテナは、発信元コンテナに関する情報を選び出してアクセスできるようになります。 リンクの生成には --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
これにより、新しい web コンテナが、直前に生成した db コンテナにリンクされます。
--link フラグは以下のような書式です。
--link <name または id>:alias
ここで name はリンクするコンテナの名前を指定します。
また alias はリンク名に対するエイリアス名の定義です。
このエイリアス名は簡単に利用することができます。
--link フラグは以下の書式でも構いません。
--link <name または 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 データベースを、ネットワーク上に公開していなくても構わないということです。
情報元のコンテナから受信先のコンテナに公開される接続情報は、以下の 2 つの手段を通じて受け渡されます。
環境変数
/etc/hostsファイルの更新
環境変数¶
コンテナをリンクすると、環境変数が数種類作り出されます。
Docker は --link パラメータに基づいて、対象とするコンテナ上に自動的に環境変数を作り出すものです。
また発信元コンテナからは、Docker がもともと提供している環境変数もすべて公開されています。
そういった環境変数は以下に基づくものです。
情報元のコンテナにおける Dockerfile に記述された
ENVコマンド情報元のコンテナを
docker runによって起動する際の、-e,--env,--env-fileオプション
このような環境変数があることによって、発信元コンテナに関する情報を、目的としているコンテナ内部においてプログラムレベルで検出できるようになります。
警告
コンテナ内の環境変数のうち Docker がもともと提供している環境変数はすべて、リンクしているどのコンテナからも利用可能である点を、十分に留意しておいてください。 その環境変数の中に重要な機密情報が含まれていたら、重大なセキュリティ問題にもなります。
--link パラメータに指定されたコンテナに対しては、<alias>_NAME という名前の環境変数が定義されます。
たとえば web という名前の新たなコンテナが、--link db:webdb という指定を通じてデータベースコンテナ db にリンクしているとします。
このとき web コンテナ内には WEBDB_NAME=/web/webdb という環境変数が生成されます。
さらに情報発信元となるコンテナが公開しているポートに対しても、環境変数が定義されます。 各変数には一意なプリフィックスがつけられます。
<name>_PORT_<port>_<protocol>
プリフィックスは以下のものから構成されます。
<name>:--linkパラメータによって指定されたエイリアス名。 (たとえばwebdb)<port>: 公開されているポート番号。<protocol>: TCP、 UDP いずれかのプロトコル。
このプリフィックスの書式から、以下の 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 つのポートを公開していたとすると、1 つのポートに対して 3 つの環境変数、つまり全部で 12 個の環境変数が定義されることになります。
さらに <alias>_PORT という環境変数も生成されます。
この変数には、発信元コンテナの一番初めの公開ポートを用いた URL が定義されます。
この「一番初めの」というのは、公開ポート番号の中で最も小さなものを指します。
たとえば WEBDB_PORT=tcp://172.17.0.82:5432 という変数があったとして、このポートが tcp、udp の双方で利用されている場合、tcp が設定されます。
最後に、発信元コンテナにおいて Docker が元から定義している環境変数が、対象とするコンテナ上の環境変数として公開されます。
各変数に対しては、対象コンテナ上に <alias>_ENV_<name> という変数が生成されます。
この変数の値は、発信元コンテナが起動する際に、Docker が利用した値が設定されます。
データベースの例に戻ります。
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
. . .
この出力から、情報元である db コンテナに関して必要となる情報が、環境変数としていくつも生成されているのがわかります。
各環境変数には 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 つの設定を見ることができます。
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 コマンド実行において、/etc/hosts の設定項目を利用しました。
そしてそれは 172.17.0.5 であることがわかりました。
このように /etc/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/