概要
Docker 1.10からユーザ定義のネットワークでは内蔵DNSサーバが用意され、名前解決ができるということを以下の記事で述べました。
実は単に名前解決ができるだけでなく、Service Discoveryとしても機能するのでその紹介をします。
環境
- Docker 18.03.1-ce
- docker-compose 1.21.1
3種類のservice discovery
dockerのドキュメントには以下のように書いてあります。
embedded DNS server which provides built-in service discovery for any container created with a valid
name
ornet-alias
or aliased bylink
.
ref: Embedded DNS server in user-defined networks | Docker Documentation
つまり
- サービス名
- net-alias名
- link名
を引けばServiceDiscoveryができるということですね。
検証
nameを使ったService Discovery
まずはサービス名を使った検証を行います。
docker-compose.yml
localnet
というネットワーク名でfront-proxyとbackendサーバを用意します。
backendの方にbackend
というnetwork aliasを付ける。
version: '2' services: front-proxy: image: nginx container_name: front-proxy networks: - localnet backend: image: nginx networks: - localnet networks: localnet: {}
front-proxyからbackendをdig
デフォルトのnginx-alpineにはdigがないので、インストールします。
# apt-get install dnsutils
digでbackend
を引いてきます。
# dig backend ; <<>> DiG 9.10.3-P4-Debian <<>> backend ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58740 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;backend. IN A ;; ANSWER SECTION: backend. 600 IN A 172.19.0.3 ;; Query time: 1 msec ;; SERVER: 127.0.0.11#53(127.0.0.11) ;; WHEN: Mon Jun 04 14:28:03 UTC 2018 ;; MSG SIZE rcvd: 48
1台用意されていたバックエンドのnginxのIPが返りました。
スケールしてdig
docker-composeのscale機能でバックエンドのサーバを増やします。
$ docker-compose up --scale backend=3 -d
先程のようにdigしてみます。
# dig backend ; <<>> DiG 9.10.3-P4-Debian <<>> backend ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54302 ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;backend. IN A ;; ANSWER SECTION: backend. 600 IN A 172.18.0.3 backend. 600 IN A 172.18.0.5 backend. 600 IN A 172.18.0.4 ;; Query time: 1 msec ;; SERVER: 127.0.0.11#53(127.0.0.11) ;; WHEN: Mon Jun 04 14:38:47 UTC 2018 ;; MSG SIZE rcvd: 94
3台すべて引くことができました。
このように動的にサーバのIPを引けるのはまさしくServiceDiscoveryの機能ですね。
ちなみにこの機能、実は次で説明するnet-aliasの機能を使っています。inspectするとaliasが設定されていることが分かります。
"Networks": { "test_localnet": { "IPAMConfig": null, "Links": null, "Aliases": [ "1f192383c18c", "backend" ], "NetworkID": "1a962438f19eb63582d7ca65cb1249dd2520f0ff15dd4846960f084d99bda530", "EndpointID": "b7351c7b02ebaa188fab9d94cc3f3072e7aea26d2fad48e9ca7360197eb3054b", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.4", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:12:00:04", "DriverOpts": null } }
net-aliasを使ったService Discovery
--network-alias
というオプションを付けると、そのalias名でIPを引くことができます。
これは先程のサービス名のケースに加えて複数のサービスに同じaliasをつけることができ、そのalias名でDNSを引くと複数のサービスのコンテナIPが返ってきます。
backend2
というサービスを追加して、同じaliasにします。
version: '2' services: front-proxy: image: nginx container_name: front-proxy networks: - localnet backend: image: nginx networks: localnet: aliases: - backend # here backend2: image: nginx networks: localnet: aliases: - backend # here networks: localnet: {}
digしてみます。
# dig backend ; <<>> DiG 9.10.3-P4-Debian <<>> backend ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18933 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;backend. IN A ;; ANSWER SECTION: backend. 600 IN A 172.18.0.3 backend. 600 IN A 172.18.0.4 ;; Query time: 1 msec ;; SERVER: 127.0.0.11#53(127.0.0.11) ;; WHEN: Mon Jun 04 23:46:02 UTC 2018 ;; MSG SIZE rcvd: 71
このように別のサービスでもIPを引けるようになります。
linksを使ったService Discovery
links機能によってサービス名によるServiceDiscoveryと同じことができます。スケールさせてもそのlinks名で引けばちゃんと複数IPとれます。
ではnet-aliasのように複数サービスに同じlink名だとどうでしょうか?
docker-compose.yml
linksで複数のサービスに同じaliasをつけてみます。
version: '2' services: front-proxy: image: nginx container_name: front-proxy networks: - localnet links: - web1:backend - web2:backend web1: image: nginx networks: - localnet web2: image: nginx networks: - localnet networks: localnet: {}
digしてみる
# dig backend ; <<>> DiG 9.10.3-P4-Debian <<>> backend ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17331 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;backend. IN A ;; ANSWER SECTION: backend. 600 IN A 172.18.0.3 ;; Query time: 1 msec ;; SERVER: 127.0.0.11#53(127.0.0.11) ;; WHEN: Tue Jun 05 00:29:09 UTC 2018 ;; MSG SIZE rcvd: 48
これもnet-aliasと同じようにできるのでは、と期待しましたがweb2
のみでした。上書きされるのかもしれません。
Networkのaliasも設定はされません。
$ docker inspect test_web_1 ... "Networks": { "test_localnet": { "IPAMConfig": null, "Links": null, "Aliases": [ "1fcde37f3bc8", "web1" // web1だけ。backendは付かない ], "NetworkID": "dd9189045bd4a0a5b3261c18f301f2075e19a94ad62957d112a9dbe8c7848c4d", "EndpointID": "2aca15273b355bfb6d005a0b0cfc64e2afd8e581c74364b52a5c0fefa8d3b6a3", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:12:00:02", "DriverOpts": null } }
またlinks機能は設定したコンテナでしか参照できないので、あまり使い勝手はよくありません。
まとめ
Dockerの埋め込みDNSを使ったService Discoveryを紹介しました。
net-alias機能によって、スケールさせたり別サービスだとしてもまとめてIPを引けることが分かりました。
わざわざConsulなど外部のService Discoveryを用意しなくても、場合によってはdockerのみで対応できそうです。