例えば、Webアプリケーションを作成する際のDocker構成の一例としてデータベース(DB)機能のみのコンテナを起動し、WebアプリコンテナからDBコンテナにアクセスする際の方法として、ホストネットワークIPへバインディングせずに、docker runサブコマンドのlinkオプションを活用する方法がある。本記事は公式mysqlサーバコンテナを作成しlinkオプションで起動したコンテナからサーバへ接続する手法を紹介する。尚、参考にした公式ドキュメントリンクは記事末尾を参照すること。また、使用docker engine versionは1.9.1。
linkオプションの機能
仮にリンクされる側のコンテナ(DBサーバ等)をsource、リンクする側のコンテナ(Webアプリ、クライアント等)をrecipientと置いた時、linkオプションがrecipientコンテナに提供する機能は下記の通り。
- sourceコンテナのIPアドレス、EXPOSEしているポート、プロトコルをrecipientコンテナの環境変数に登録
- sourceコンテナの環境変数をrecipientコンテナの環境変数に登録
- sourceコンテナのIPアドレスをrecipientコンテナの/etc/hostsへ登録
DockerコンテナのIPアドレスはdocker run時にランダムに割り振られ、他のコンテナから仮想ブリッジ経由で当該IPにアクセスする際は、上記の様なlink機能が必要となる。
以下にmysqlコンテナを用いて、上記機能の確認結果を示す。
尚、公式mysqlコンテナのリンクは下記の通り。
https://hub.docker.com/_/mysql/
DockerfileのEXPOSE指定は3306ポートとなる。
mysqlサーバコンテナの作成
$ docker run -d --name mysql01 -e MYSQL_ROOT_PASSWORD=toor mysql:latest afceca423dc989776dd067e5779b5560033b0f10e294055de63a8a9ec7e60704 $ docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES afceca423dc9 mysql:latest "/entrypoint.sh mysql" About a minute ago Up About a minute 3306/tcp mysql01
-eオプションで指定している環境変数MYSQL_ROOT_PASSWORDはmysqlのrootパスワードとなる。ちなみに、toorはBlack hat(現kali)でデフォルトで設定されているパスワード。私はテスト用だと良く使用する。
続いて、mysql01コンテナ上のbashからコンテナのステータスを確認する。
$ docker exec -it mysql01 /bin/bash root@afceca423dc9:/# ps -efl F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 4 S mysql 1 0 0 80 0 - 365656 poll_s 05:54 ? 00:00:00 mysqld 4 S root 105 0 0 80 0 - 5051 wait 05:58 ? 00:00:00 /bin/bash 0 R root 114 105 0 80 0 - 4371 - 05:58 ? 00:00:00 ps -efl root@afceca423dc9:/# env HOSTNAME=afceca423dc9 MYSQL_VERSION=5.7.10-1debian8 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ SHLVL=1 HOME=/root MYSQL_MAJOR=5.7 MYSQL_ROOT_PASSWORD=toor _=/usr/bin/env root@afceca423dc9:/# mysql -u root -ptoor mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 Server version: 5.7.10 MySQL Community Server (GPL) Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.03 sec) mysql> quit Bye root@afceca423dc9:/# exit exit $ docker ps -l ← execでbashを起動したので、exit後もコンテナがUp状態であることを念のため確認。 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES afceca423dc9 mysql:latest "/entrypoint.sh mysql" 5 minutes ago Up 5 minutes 3306/tcp mysql01
psコマンドにてコンテナ上でmysqldが稼働していること、envコマンドにてコンテナ上にMYSQL_ROOT_PASSWORDが登録されていること、mysqlコマンドにてmysqldへログインしsqlを打鍵できることを確認できる。
mysqlクライアントコンテナの作成
$ docker run --link mysql01:db -it --rm mysql:latest /bin/bash
mysqlクライアントとしてのコンテナが必要である為、手っ取り早くmysqlコマンドが使える公式mysqlコンテナを活用。エイリアス名はdb。–rmオプションを付けることでコンテナ終了時、すなわち/bin/bash終了時にコンテナを削除する設定とする。
root@1f7e94bb29f4:/# env HOSTNAME=1f7e94bb29f4 DB_NAME=/stoic_wescoff/db TERM=xterm MYSQL_VERSION=5.7.10-1debian8 DB_PORT=tcp://172.17.0.4:3306 DB_PORT_3306_TCP_PORT=3306 DB_PORT_3306_TCP_PROTO=tcp DB_ENV_MYSQL_ROOT_PASSWORD=toor PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ DB_PORT_3306_TCP_ADDR=172.17.0.4 HOME=/root SHLVL=1 DB_PORT_3306_TCP=tcp://172.17.0.4:3306 MYSQL_MAJOR=5.7 DB_ENV_MYSQL_VERSION=5.7.10-1debian8 DB_ENV_MYSQL_MAJOR=5.7 _=/usr/bin/env
上記環境変数から分かるとおり、source側のコンテナ情報はDB_PORT_3306〜で登録され、source側の環境変数もDB_ENV_〜で登録されている。
参考) 公式ガイド: Legacy container links
_PORT_ _ The components in this prefix are: the alias specified in the --link parameter (for example, webdb) the number exposed a which is either TCP or UDP
hostsファイルにもコンテナ名(mysql01)、エイリアス名(db)、コンテナID(afceca423dc9)でホストエントリが登録されている。
root@ac2ccafabe6d:/# cat /etc/hosts 172.17.0.2 ac2ccafabe6d 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.4 db afceca423dc9 mysql01 root@ac2ccafabe6d:/# ping mysql01 PING db (172.17.0.4): 56 data bytes 64 bytes from 172.17.0.4: icmp_seq=0 ttl=64 time=0.073 ms 64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.083 ms 64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.084 ms ^C--- db ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.073/0.080/0.084/0.000 ms root@ac2ccafabe6d:/#
mysqlサーバコンテナへの接続
root@1f7e94bb29f4:/# mysql -h"$DB_PORT_3306_TCP_ADDR" -P"$DB_PORT_3306_TCP_PORT" -uroot -p"$DB_ENV_MYSQL_ROOT_PASSWORD" mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.10 MySQL Community Server (GPL) Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases -> ; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.00 sec) mysql> exit Bye root@1f7e94bb29f4:/# exit exit $
linkを用いたコンテナ構成で本番デプロイを行う際、環境変数に渡す情報と、コンテナの起動順序に考慮が必要となる。大量のコンテナを管理する場合にDocker ComposeやKubernetesが必要なる理由が良くわかる。
recipientコンテナ上の/etc/hostsファイルの動的更新
仮にmysql01:dbコンテナのみをrestartした場合、再割り当てされたIPアドレス情報はrecipientコンテナの/etc/hostsファイルに即時反映される。但し、環境変数<エイリアス名>_PORT_3306_TCP_ADDRは当該プロセスが終了するまでは変更されない。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7cd2a1a20986 mysql:latest "/entrypoint.sh /bin/" About a minute ago Up About a minute 3306/tcp berserk_wright afceca423dc9 mysql:latest "/entrypoint.sh mysql" 3 hours ago Up 3 hours 3306/tcp mysql01 [vagrant@localhost ~]$ docker restart mysql01 mysql01
再度、berserk_wright上でhostsを確認すると、mysql01のIPが172.17.0.4から172.17.0.3に変更されているが、DB_PORT_3306_TCP_ADDRは変更されていない。
root@7cd2a1a20986:/# cat /etc/hosts 172.17.0.2 7cd2a1a20986 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.3 db afceca423dc9 mysql01 root@7cd2a1a20986:/# env HOSTNAME=7cd2a1a20986 DB_NAME=/berserk_wright/db TERM=xterm MYSQL_VERSION=5.7.10-1debian8 DB_PORT=tcp://172.17.0.4:3306 DB_PORT_3306_TCP_PORT=3306 DB_PORT_3306_TCP_PROTO=tcp DB_ENV_MYSQL_ROOT_PASSWORD=toor PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ DB_PORT_3306_TCP_ADDR=172.17.0.4 HOME=/root SHLVL=1 DB_PORT_3306_TCP=tcp://172.17.0.4:3306 MYSQL_MAJOR=5.7 DB_ENV_MYSQL_VERSION=5.7.10-1debian8 DB_ENV_MYSQL_MAJOR=5.7 _=/usr/bin/env root@7cd2a1a20986:/# ping mysql01 PING db (172.17.0.3): 56 data bytes 64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.085 ms 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.083 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.082 ms ^C--- db ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.082/0.083/0.085/0.000 ms root@7cd2a1a20986:/#
そう考えると、コード中で使用するsourceのIPアドレス指定は環境変数よりもhostsに記載のコンテナ名、エイリアス名の方が、コンテナの動的なIP変更にも耐えられる設計となり良いかと思う。