アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

複数のdocker-composeコンテナ間で名前で通信できるようにする

この記事は actindi Advent Calendar 2018 の21日目の記事です。

年の瀬の押し迫ったこの時期、クリスマスも目の前というのに普通の技術ブログでお茶を濁すyamamotoですw
ちなみに本日弊社は恒例の納会をやる予定です。社内でパーティーです。
みなさま今年一年お疲れさまでした&ありがとうございました!

さて、docker-composeで一斉構築されるコンテナは、DNS機能を持つ同じネットワーク内に配置されるので、コンテナ名を使って相互にアクセスが可能です。
しかし複数の docker-compose.yml ファイルを使って別々に立ち上げたサーバー群は、通常それぞれ別のネットワークに配置されてしまいます。
すると、お互いコンテナ名でアクセスできないため、コンテナのIPアドレスを固定するなどの工夫が必要になります。

なんとかうまいことコンテナ名を使って簡単にアクセスできないものか、と考えていたのですが、いっそ同じネットワークに入れちゃえば内部DNSも使えたりしないかな、と思ってやってみました。

キモは、docker-composeを実行する際、-pオプションを指定することです。
http://docs.docker.jp/compose/reference/overview.html#docker-compose
-pオプションは「別のプロジェクト名を指定」とあるように、デフォルトでないプロジェクト名を指定します。

通常、docker-composeでコンテナを立ち上げると、ディレクトリ名がベースの名前になり、コンテナ名のプレフィックスや、ネットワーク名にもなります。
プロジェクト名を指定することでベースの名前を変えることができるので、これを都度指定すれば、同じネットワークに組み入れることが可能になります。

では実際にやってみます。
今回は簡単に実証するため、nginxのdocker-composeを二つ用意します。

├── nginx-a
│      └── docker-compose.yml
└── nginx-b
       └── docker-compose.yml

nginx-a/docker-compose.yml

version: '3'
services:
  nginx-a:
    image: nginx

nginx-b/docker-compose.yml

version: '3'
services:
  nginx-b:
    image: nginx

まず、nginx-aフォルダーで普通にdocker-composeを走らせてみます。

nginx-a$ docker-compose up -d
Creating network "nginx-a_default" with the default driver
(略)
Creating nginx-a_nginx-a_1 ... done

するとこのようになり、フォルダーの名前が勝手にネットワーク名になってしまいました。

次に、-pオプションを付けてdocker-composeを走らせます。

nginx-a$ docker-compose -p test up -d
Creating network "test_default" with the default driver
Creating test_nginx-a_1 ... done

-pオプションで指定したプロジェクト名をベースにしたネットワーク名で出来上がりました。

nginx-bの方でも同じように実行してみます。

nginx-b$ docker-compose -p test up -d
: Found orphan containers (test_nginx-a_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Recreating test_nginx-b_1 ... done

同じプロジェクトにすでにコンテナがあるよ、と言われますが望むところです。

これで、同じネットワーク内にコンテナが二つ組み入れられました。
ネットワークを確認すると、両方とも同じネットワークゾーンに居るのがわかります。

$ docker network inspect test_default
[
    {
        "Name": "test_default",
        "Id": "97f11a906ac3721a445ba983977be032917a68677c22b744a2d3a1c9d7695268",
        "Created": "2018-11-27T19:54:30.81439479+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.23.0.0/16",
                    "Gateway": "172.23.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "31c0824dfc7e5ef80b8b6b0e21b99686656780284c06ee0d75c928ec1b4c76fb": {
                "Name": "test_nginx-a_1",
                "EndpointID": "1f506248fcf2c8a3fc3e7da9f628edf59b758e37d93c08005349fc766b2ffaab",
                "MacAddress": "02:42:ac:17:00:02",
                "IPv4Address": "172.23.0.2/16",
                "IPv6Address": ""
            },
            "a833f28764d054020167469fd96e9ae09c23ae10cce5467bb790e8dc59c140da": {
                "Name": "test_nginx-b_1",
                "EndpointID": "cae382ff416d18708cb5f628c9ff4b3ef3b96e8c6655cb6d1d26624f822f0d89",
                "MacAddress": "02:42:ac:17:00:03",
                "IPv4Address": "172.23.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "test"
        }
    }
]

この状態だと、お互いのサーバーにアクセスするのにコンテナ名が使えます。
試してみましょう……と思ったらnginxのイメージには余計なソフトが何も入っていないので、curlをインストールすることにします。

$ docker exec -it test_nginx-a_1 /bin/bash
root@31c0824dfc7e:/# apt-get update && apt-get install -y curl
(略)
root@31c0824dfc7e:/# curl test_nginx-b_1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

nginx-b側にコンテナ名でアクセスすることができました。

ではDNS的にはどうなっているかを見てみます。
やはり必要なコマンドが入っていないので、dnsutilsを入れてdigコマンドを使えるようにします。

root@31c0824dfc7e:/# apt-get install -y dnsutils
(略)
root@31c0824dfc7e:/# dig test_nginx-a_1

; <<>> DiG 9.10.3-P4-Debian <<>> test_nginx-a_1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63522
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;test_nginx-a_1.                        IN      A

;; ANSWER SECTION:
test_nginx-a_1.         600     IN      A       172.23.0.2

;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Tue Nov 27 11:05:39 UTC 2018
;; MSG SIZE  rcvd: 62
root@31c0824dfc7e:/# dig test_nginx-b_1

; <<>> DiG 9.10.3-P4-Debian <<>> test_nginx-b_1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56026
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;test_nginx-b_1.                        IN      A

;; ANSWER SECTION:
test_nginx-b_1.         600     IN      A       172.23.0.3

;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Tue Nov 27 11:05:43 UTC 2018
;; MSG SIZE  rcvd: 62

見ての通り、内部DNSがコンテナ名での名前解決をできるようにしてくれています。
これでdocker-compose環境の使いまわしも簡単にできますね。

アクトインディでは、dockerを勉強したいインフラエンジニアもひそかに募集してます!!
気になったら、募集ページ下のエントリーフォームからお問い合わせください!
https://actindi.net/recruit/engineer/