Dockerコンテナをホスト名で参照できるDNSサーバコンテナ「dnsdock」を使う

ホストとなるサーバ上にA,Bの2つのコンテナが稼働しているとき、片方のコンテナからもう片方のコンテナを参照したいときは、簡単な方法はdockerコマンドの–linkオプションを使います。

これとは別に、ホスト名を使うことにより各コンテナを参照することができるコンテナがdnsdockです。
これを使うと–linkオプションなしで相互のコンテナにアクセスできます。
dnsdockはskydockをもとに簡易化したものです。

※コンテナ同士のやり取りは前提としてDockerデーモンのiccパラメータがtrue(デフォルト)で、アクセスされたいコンテナがexposeでポートをさらしている必要があります。

使用例

前提

  • ホストのOSはubuntu14.04
  • ホストのプロンプトを(host),コンテナのプロンプトを(コンテナ名)とする
  • rootは#、ユーザーは$とする

今回は、php(php:5-apache)とmysql(mysql:5.6)のコンテナを使い、

  • ホストからmysqlコマンドでmysqlコンテナにアクセス
  • ホストからcurlコマンドでphpコンテナにアクセス
  • phpコンテナからでmysqlコンテナにアクセス

をしてみます。

1.ホスト側の設定(要root)

Dockerのネットワークを172.17.0.1/24にして、コンテナが参照するDNSを172.17.0.1にする。

  • Dockerデーモンの起動オプションにbipとdnsを加えて、サービスを再起動

    /etc/default/docker

    DOCKER_OPTS="--bip=172.17.0.1/24 --dns=172.17.0.1 --dns=8.8.8.8"
    

    ※各コンテナは172.17.0.1をデフォルトのDNSとしてdnsdockを通して名前解決を行うが、dnsdockが停止していると名前解決が行えないので予備も設定しておく

    (host)# service docker restart
    
  • ネームサーバに172.17.0.1を/etc/resolv.confのnameserverの先頭に加える。直接加えると再起動時に消えるので、resolvconfを利用する

    /etc/resolvconf/resolv.conf.d/head

    nameserver 172.17.0.1
    
    (host)# resolvconf -u
    

2.作業領域と確認用コードの作成

(host)$ mkdir work
(host)$ cd work
(host)$ mkdir src
(host)$ echo '<?php echo "Hello World\n"; ' > src/index.php

3.dnsdockコンテナの起動

(host)$ docker run -d --name dnsdock -v /var/run/docker.sock:/var/run/docker.sock -p 172.17.0.1:53:53/udp aacebedo/dnsdock:latest-amd64

(追記 2016/10/14)Githubのページがtonistiigi/dnsdockからaacebedo/dnsdockに変更されたのに伴ってコンテナイメージをaacebedo/dnsdock、バージョンをDocker Hubに従ってlatest-amd64に変更しました。
(追記 2016/8/24)issueがcloseされ、clouddynamics/dnsdockがなくなりました
※dnsdockの本家は tonistiigi/dnsdock だが、ホストからアクセスする際にバグがあり、対応されたものが clouddynamics/dnsdock にあるためコンテナイメージはそちらを利用しています。
参考:dig dnsdocker.docker works, curl dnsdocker.docker doesn’t · Issue #34 · tonistiigi/dnsdock

  • digコマンドで名前が解決できるか確認

    (host)$ dig *.docker

    ; <> DiG 9.9.5-3ubuntu0.6-Ubuntu <> *.docker
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24923
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;*.docker.                      IN      A
    
    ;; ANSWER SECTION:
    *.docker.               0       IN      A       172.17.42.2
    
    ;; Query time: 1 msec
    ;; SERVER: 172.17.42.1#53(172.17.42.1)
    ;; WHEN: Thu Jan 14 20:12:05 JST 2016
    ;; MSG SIZE  rcvd: 50
    

4.MySQLコンテナとPHPコンテナの起動

(host)$ docker run -d --name some-mysql -e MYSQL_ROOT_PASSWORD=mysqlpass mysql:5.6
(host)$ docker run -d --name some-php -v $(pwd)/src:/var/www/html -p 80:80 php:5-apache
  1. 現在起動中のコンテナの確認

    (host)$ docker ps

    CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                    NAMES
    d70f295f19fb        php:5-apache            "apache2-foreground"     36 seconds ago      Up 34 seconds       0.0.0.0:80->80/tcp       some-php
    2b1323183779        mysql:5.6               "/entrypoint.sh mysql"   3 minutes ago       Up 3 minutes        3306/tcp                 some-mysql
    7258ecfbfd04        tonistiigi/dnsdock   "/go/bin/dnsdock"        7 minutes ago       Up 7 minutes        172.17.42.1:53->53/udp   dnsdock
    
  2. 起動したコンテナの名前解決を確認

    ホスト名は<anything>.<container-name>.<image-name>.<environment>.<domain>というルールになっており、デフォルトだと<domain>はdocker、<environment>は空文字列のため、<container-name>.<image-name>.dockerでアクセスできる。

    MySQLコンテナはmysqlイメージを使ってsome-mysqlという名前で起動したため、ホスト名はsome-mysql.mysql.docker

    (host)$ dig some-mysql.mysql.docker

    ; <> DiG 9.9.5-3ubuntu0.6-Ubuntu <> some-mysql.mysql.docker
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14084
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;some-mysql.mysql.docker.       IN      A
    
    ;; ANSWER SECTION:
    some-mysql.mysql.docker. 0      IN      A       172.17.42.3
    
    ;; Query time: 0 msec
    ;; SERVER: 172.17.42.1#53(172.17.42.1)
    ;; WHEN: Thu Jan 14 20:20:11 JST 2016
    ;; MSG SIZE  rcvd: 80
    

    同様にPHPコンテナはphpイメージを使って、some-phpという名前で起動したのでホスト名はsome-php.php.docker

    (host)$ dig some-php.php.docker

    ; <> DiG 9.9.5-3ubuntu0.6-Ubuntu <> some-php.php.docker
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30088
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;some-php.php.docker.           IN      A
    
    ;; ANSWER SECTION:
    some-php.php.docker.    0       IN      A       172.17.42.4
    
    ;; Query time: 0 msec
    ;; SERVER: 172.17.42.1#53(172.17.42.1)
    ;; WHEN: Thu Jan 14 20:21:15 JST 2016
    ;; MSG SIZE  rcvd: 72
    

5.ホストからPHPコンテナにホスト名でアクセスしてみる

(host)$ curl http://some-php.php.docker/index.php

Hello World

6.ホストからmysqlコマンドでMySQLコンテナにホスト名でアクセスしてみる

mysqlコマンドはあらかじめインストールしておく必要があります。
(ubuntu14.04ならapt-get install mysql-client-core-5.6)

(host)$ mysql -h some-mysql.mysql.docker -u root --password=mysqlpass

7.phpコンテナからmysqlにアクセス

7.1 PHPコンテナにPDOとMySQLのモジュールを組み込む

php:5-apacheにはPDOとMySQLのモジュールが組み込まれていないので、組み込む必要がある。

方法1 モジュール入りカスタムイメージを使う
  1. Dockerfileを作成する

    Dockerfile

    FROM php:5-apache
    RUN docker-php-ext-install pdo pdo_mysql
    
  2. イメージを作成する
    (host)$ docker build -t php:custom  .
    
  3. 動かしているsome-phpコンテナを終了させて、代わりにカスタムイメージで起動する
    (host)$ docker stop some-php
    (host)$ docker rm some-php
    (host)$ docker run -d --name some-php -v $(pwd)/src:/var/www/html -p 80:80 php:custom
    
方法2 現在動いているコンテナにモジュールをインストールする
  1. some-phpコンテナに入る
    (host)$ docker exec -it some-php bash
    
  2. モジュールをインストールする
    (some-php)$ docker-php-ext-install pdo pdo_mysql
    (some-php)$ exit
    
  3. コンテナ再起動
    (host)$ docker restart some-php
    

7.2 index.phpをPDOを使ってMySQLにアクセスするプログラムに書き換える

src/index.php

<?php

    $pdo = new PDO('mysql:host=some-mysql.mysql.docker;dbname=mysql', 'root', 'mysqlpass');
    $sth = $pdo->query("show tables");
    $sth->execute();
    $result = $sth->fetchAll();
    print_r($result);

7.3 ホストからアクセス

(host)$ curl http://some-php.php.docker/index.php

Array
(
    [0] => Array
        (
            [Tables_in_mysql] => columns_priv
            [0] => columns_priv
        )

    [1] => Array
        (
            [Tables_in_mysql] => db
            [0] => db
        )
     :
     :
     :

WEBインタフェース

dnsdockにはRESTインタフェースを持っているので、curlなどで問い合わせやデータの更新ができます。

tonistiigi/dnsdock#HTTP Server

整形にjqコマンドを使用しています。

コンテナの一覧

curl -s http://dnsdock.docker/services|jq .

{
  "672963efeef98b3c473f87f7ede66e51f661cc6f5f28075c79ec44c633d2a564": {
    "Aliases": [],
    "Ttl": -1,
    "Ip": "172.17.42.2",
    "Image": "dnsdock",
    "Name": "dnsdock"
  },
  "2d17b46d944919797ed4f62d9c763e240cf2ed511573f22b438b07ba3239f77b": {
    "Aliases": [],
    "Ttl": -1,
    "Ip": "172.17.42.4",
    "Image": "php",
    "Name": "some-php"
  },
  "263c0325f15f0f4c95f68f1975df5a50104ca766529c772d29d9a1357b8fab17": {
    "Aliases": [],
    "Ttl": -1,
    "Ip": "172.17.42.3",
    "Image": "mysql",
    "Name": "some-mysql"
  }
}

参考

(追記 2016/10/14)
記事執筆時はアドレスとして172.17.42.1を使用していましたが、

ERROR: for dnsdock  Cannot start service dnsdock: driver failed programming external connectivity

というエラーが出るようになったため、下記及びaacebedo/dnsdockを参考に172.17.0.1に変更したらうまく動作するようになりました

1.9: Default docker0 IP is not 172.17.42.1 for new installs · Issue #17305 · docker/docker

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中