Docker: コンテナの連結


http://docs.docker.com/userguide/dockerlinks/

# 1. ネットワークポート割り当てのリフレッシャー
デフォルトの -p フラグは、ホストマシン上で指定されたポートを、すべてのインターフェースに結びつける。しかし、特定のインターフェースを指定することも可能である。

例1) ホストマシン上のインターフェース localhost か 127.0.0.1 上のポート 5000 を、コンテナ内部のポート 5000 に結びつける

```
$ sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
```

例2) コンテナが使うポート 5000 を、localhost とだけ指定しても、動的にポートを割り当てられる

```
$ sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py
```

例3) また /udp を末尾に追加することで、UDP ポートに結びつけることができる

```
$ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
```

# 2. linking sysytemを使った連携
ネットワークポートのマッピングがコンテナを接続するための唯一の方法ではない。Dockerはlinking systemという機能を備えており、この機能により複数のコンテナを連携し、接続情報をお互いのコンテナに送ることができる。コンテナがリンクされた時、ソースコンテナについての情報は受給側のコンテナに送信される。

#### 2.1. ネーミングの重要性
Linkの構築は、Dockerはコンテナ名に依存する。自動的にコンテナ名が生成されるのを既に見ている。コンテナ名は自分で付けることもできる。コンテナに名前を付けることにより2つ機能を提供する。
何か特定の機能を持ったコンテナに分かりやすい名前をつけるとそれらを簡単に覚えられるので役にたつ。例えばWebアプリケーションが動作するコンテナにwebと名付けるなど。
名前付けはDockerへ他のコンテナへの参照ポイントを提供する。例えば、web というコンテナを db というコンテナにLinkする場合、コンテナへの名前付けは—nameフラグで指定する。ここではwebという名前を付けている。

```
# docker run -d -P --name web training/webapp python app.py
b5b8ae5e83dac45c09c0cb5030b1497f18c3b24a3a42f06051d64eabdda4f590
```

docker psでコンテナ名を確認できる。(inspectでも可能)

```
# docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
b5b8ae5e83da        training/webapp     "python app.py"     22 seconds ago      Up 20 seconds       0.0.0.0:32770->5000/tcp   　web
```

※コンテナ名は一意である必要がある。もしコンテナ名を再利用したい場合、新しいコンテナを作る前に古いコンテナは削除しないといけない。
コンテナの削除はdocker rmで可能だが、docker run コマンドに --rm フラグを使う方法もあり、これは、それが止まったら、直ぐにコンテナが削除。

#### 2.2. Linkを使った接続
Linkにより、コンテナ同士が互いに発見することが可能となり、コンテナ間でセキュアに情報交換を行うことができる。Linkをセットアップする時、ソースコンテナとレピシエントコンテナ間でコンジット（パイプ）を作成する。レピシエントはソースの情報を選択しアクセスすることができる。Linkを作成するには、--linkフラグを使用する。

dbという名前を付けた新しいコンテナ(dbコンテナ)をtraining/postgresイメージから生成する。このコンテナにはPostgreSQLが含まれている。

```
# docker run -d --name db training/postgres
```

webという名前を付けたコンテナ(webコンテナ)を作成し、dbコンテナとlinkさせる。--linkフラグのフォームは”--link <コンテナ名 or コンテナID>:alias(link名のエイリアス)”である。

```
# docker run -d -P --name web --link db:db training/webapp python app.py
840e5af8046a4ec4ef0d03f7f06f7f1efdfee0c4c37f044ba7329b427b17c62c
```

docker inspectコマンドを利用して、webコンテナとlinkしているコンテナを検知する。webコンテナがdbコンテナ(web/db)とリンクされていることを確認できる。これはdbコンテナに関する情報へアクセス可能であることを意味している。

```
# docker inspect -f "{{ .HostConfig.Links }}" web
[/db:/web/db]
```

コンテナをlinkすることは実際に何を示しているのか？linkはソースコンテナが自身の情報をレピシエントコンテナに知らせることができるようにするもの。この例では、レピシエント(webコンテナ)はソース（dbコンテナ）の情報へアクセスすることができる。これを可能とするために、Dockerはセキュアなトンネルをコンテナ間に作り、ポートを開放することなく情報を参照できる。dbコンテナを起動した際には-Pや-pでポートを開放していない。これがlinkingの大きなメリットである。ソースコンテナはPostgreSQLのポートをネットワーク上にオープンする必要がなくなるのである。
Docker はレピシエントコンテナからソースコンテナに接続するための情報として、2つ提供している。
・環境変数
・/etc/hostsのアップデート

**【環境変数】**
Dockerはコンテナをlinkするとき、いくつかの環境変数を生成する。Dockerは対象とするコンテ内で自動的に環境変数を作成する。全ての環境変数はlinkしたコンテナに対してアクセスできる。例えばソースコンテナのDockerfileに記載されたENVコマンド、docker runコマンドの-eや—envオプション。これらの環境変数はソースコンテナと関連するターゲットコンテナから参照することが可能である。
注意）全ての環境変数は理解できるのは、Linkしているコンテナのみである。

Dockerは<alias>_NAME環境変数にセットし、aliasの値は—linkパラメータで指定したaliasが反映される。例えば、dbコンテナとlinkする新しいコンテナ(webdb)の場合（--link db:webdb）、DockerはWEBDB_NAME=/web/webdb環境変数を生成する。
それだけでなく、いくつかの環境変数のセットも生成する。これらの環境変数は以下の書式でユニークなプレフィックスを持っている。

```
<name>_PORT_<port>_<protocol>
```
nameはエイリアス名、portは公開するポート番号、protocolはTCPやUDP。

| 環境変数 | 備考 | 
|:-----------|:------------|
| prefix_ADDR|IPアドレス。例）WEBDB_PORT_8080_TCP_ADDR=172.17.0.82| 
| prefix_PORT|ポート番号。例）WEBDB_PORT_8080_TCP_PORT=8080|   
| prefix_PROTO |プロトコル。WEBDB_PORT_8080_TCP_PROTO=tcp|  

もしコンテナが複数のポートを公開するなら、環境変数はそれぞれセットされる。例えばコンテナが4ポート公開するならDockerは12個（4portx3環境変数）の環境変数を生成する。

さらに、Dockerは<alias>_portという環境変数を生成する。これはソースコンテナの外部への最初の公開ポートのURLを含む変数である。ここでいう最初のポートは最も低いポート番号を指す。例えば、WEBDB_PORT=tcp://172.17.0.82:8080において、tcpとudp両方のポートがある場合、tcpのポートが指定される。

最後に、Dockerオリジナルの環境変数を公開する。この環境変数は<alias>_ENV_<name>という環境変数名でDockerが生成する。

```
# docker run --rm --name web2 --link db:db training/webapp env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=8dbe13c59fbe
DB_PORT=tcp://172.17.0.2:5432
DB_PORT_5432_TCP=tcp://172.17.0.2:5432
DB_PORT_5432_TCP_ADDR=172.17.0.2
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web2/db
DB_ENV_PG_VERSION=9.3
HOME=/root
```

Dockerがdbコンテナについて一連の環境変数を生成していることが確認できる。それぞれの環境変数はプリフィックスとしてDB_がついている。これは—linkフラグで指定したエイリアスの値から生成されている。もしエイリアスがdb1ならプリフィックスはDB1_となる。これらの環境変数はリンクしたコンテナからのみ利用可能であるため、セキュアに接続することができる。

** Docker環境変数の注意点）**
/etc/hostsファイルと違い、IPアドレスは環境変数格納される。そして、コンテナが再起動した際にこれらの環境変数は自動的にアップデートされない。そのため、linkされたコンテナのIPアドレスを解決するためには/etc/hostsにエントリを追加することを推奨。
※確認したところ、初回コンテナ作成時には環境変数は設定されているが、コンテナを停止、起動したときはこれらの環境変数が設定されてないようである。（コンテナを再起動すると消える）

```
# docker run --rm --name web2 --link db:db training/webapp env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=8dbe13c59fbe
DB_PORT=tcp://172.17.0.2:5432
DB_PORT_5432_TCP=tcp://172.17.0.2:5432
DB_PORT_5432_TCP_ADDR=172.17.0.2
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web2/db
DB_ENV_PG_VERSION=9.3
HOME=/root
```

```
# docker stop 8023fe16ed9a
```

```
# docker start 8023fe16ed9a
```

```
# docker exec 8023fe16ed9a env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=8023fe16ed9a
HOME=/
PG_VERSION=9.3
```

注：これらの環境変数がセットされるのは、コンテナの起動時だけです。同様に、何らかのデーモン ( sshd など ) は、生成されたシェル ( spawning shell ) に接続するときには無効にされる。

**【/etc/hostsファイルのアップデート】**
環境変数に加え、Dockerはホストのエントリを/etc/hostsファイルに追加する。

以下の例では2つのエントリが追加されていることを確認できる。一つ目はwebコンテナのコンテナIDがホスト名として登録されている。2つ目はLinkしたdbに関する情報で、Linkエイリアス名、コンテナID、コンテナ名が登録されている。

```
# docker run –t –I –rm –link db:webdb training/webapp /bin/bash
root@7aa64c25b991:/opt/webapp# cat /etc/hosts
172.17.0.3      7aa64c25b991 #コンテナID
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      webdb 8023fe16ed9a db #linkしているdbの情報が追記されている。
```

もしソースコンテナを再起動した場合、linkしたコンテナの/etc/hostsファイルは自動的に更新（ソースコンテナの新しいIPアドレスが反映）される。