概要
以前Consulの基本的な使い方を紹介しました。
このConsulに登録する各ノードに対しサービス設定をすることで、各マイクロサービスに所属しているコンテナ群のIPを取得できるようします。
それによってgRPCでの負荷分散としてのClient-side LBが、動的なコンテナに対しても可能になります。
環境
- Consul 1.1.0
- docker 18.03.1-ce
- docker-compose 1.21.1
準備
githubにデモ用のdocker-composeの設定があるのでそれを利用します。
ディレクトリ構造
以下のようにConsulのサービスを設定するためのjsonを用意します。
内容は後述します。
. ├── docker-compose.yml ├── nginx-service │ └── service.json └── redis-service └── service.json
docker-compose.yml
version: '3' services: nginx-agent-1: &nginx-agent image: consul:latest networks: - consul-demo command: "agent -retry-join consul-server-bootstrap -client 0.0.0.0" volumes: - ./nginx-service:/consul/config nginx-agent-2: <<: *nginx-agent nginx-agent-3: <<: *nginx-agent redis-agent-1: &redis-agent image: consul:latest networks: - consul-demo command: "agent -retry-join consul-server-bootstrap -client 0.0.0.0" volumes: - ./redis-service:/consul/config redis-agent-2: <<: *redis-agent redis-agent-3: <<: *redis-agent consul-server-1: &consul-server image: consul:latest networks: - consul-demo command: "agent -server -retry-join consul-server-bootstrap -client 0.0.0.0" consul-server-2: <<: *consul-server consul-server-bootstrap: <<: *consul-server ports: - "8400:8400" - "8500:8500" - "8600:8600" - "8600:8600/udp" command: "agent -server -bootstrap-expect 3 -ui -client 0.0.0.0" networks: consul-demo:
ポイントは以下です。
- configファイルはコンテナ側では
/consul/config
をマウントする。Dockerfileの方でそこを使う設定になっている - 8600/udpのポートフォワードをする。DNSの参照はudpを使うため
nginx-service/service.json
Service Definition - Consul by HashiCorpのドキュメントに従って書きます。
name
のみ必須で、あとはoptionalです。今回はtag
だけ付けました。
{ "service": { "name": "nginx", "tags": ["dev"] } }
redis-service/service.json
こちらも同様。name
をredis
にしてます。
{ "service": { "name": "redis", "tags": ["dev", "cache"] } }
動作検証
起動
docker-composeで起動します。
$ docker-compose up -d
Web UIで確認
起動中です。3台のConsul serverが互いに疎通し、リーダーが選出されるまではこの表示です。
起動が完了しました
digでDNSが使えるか確認
nginx
まずはnginxのサービスに登録されているコンテナのIPを取得します
$ dig @localhost -p 8600 nginx.service.consul ; <<>> DiG 9.10.6 <<>> @localhost -p 8600 nginx.service.consul ; (2 servers found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8981 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;nginx.service.consul. IN A ;; ANSWER SECTION: nginx.service.consul. 0 IN A 172.18.0.2 nginx.service.consul. 0 IN A 172.18.0.4 nginx.service.consul. 0 IN A 172.18.0.8 ;; Query time: 1 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Thu May 31 11:10:18 JST 2018 ;; MSG SIZE rcvd: 97
- 172.18.0.2
- 172.18.0.4
- 172.18.0.8
の3つがちゃんと取れました。
redis
次にredisサービスに登録されているコンテナのIPを取得します。
$ dig @localhost -p 8600 redis.service.consul ; <<>> DiG 9.10.6 <<>> @localhost -p 8600 redis.service.consul ; (2 servers found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19331 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;redis.service.consul. IN A ;; ANSWER SECTION: redis.service.consul. 0 IN A 172.18.0.5 redis.service.consul. 0 IN A 172.18.0.6 redis.service.consul. 0 IN A 172.18.0.3 ;; Query time: 8 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Thu May 31 11:10:06 JST 2018 ;; MSG SIZE rcvd: 97
- 172.18.0.3
- 172.18.0.5
- 172.18.0.6
の3つがちゃんと取れました。
tagでフィルタリング
例えばdev, stg, prdで環境分けしたい時にtag
を設定することでフィルタリングすることが可能です。
先程のservice.json
ではdev
やcache
と言ったtag
を付けました。
設定したcache
でフィルタ
$ dig @localhost -p 8600 cache.redis.service.consul ; <<>> DiG 9.10.6 <<>> @localhost -p 8600 cache.redis.service.consul ; (2 servers found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48848 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;cache.redis.service.consul. IN A ;; ANSWER SECTION: cache.redis.service.consul. 0 IN A 172.18.0.10 cache.redis.service.consul. 0 IN A 172.18.0.2 cache.redis.service.consul. 0 IN A 172.18.0.8 ;; Query time: 3 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Thu May 31 17:58:16 JST 2018 ;; MSG SIZE rcvd: 103
ちゃんと出ます。
設定していないhoge
でフィルタ
$ dig @localhost -p 8600 hoge.redis.service.consul ; <<>> DiG 9.10.6 <<>> @localhost -p 8600 hoge.redis.service.consul ; (2 servers found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 51300 ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;hoge.redis.service.consul. IN A ;; AUTHORITY SECTION: consul. 0 IN SOA ns.consul. hostmaster.consul. 1527757102 3600 600 86400 0 ;; Query time: 7 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Thu May 31 17:58:21 JST 2018 ;; MSG SIZE rcvd: 104
設定していないので存在しないです。
このようにtag
を設定することで柔軟にフィルタ可能になります。
まとめ
Consulでサービスを設定することで、マイクロサービスのコンテナ群のIPをDNSで取得することができました。
Kubernetesであれば
のようにheadless serviceを使えば実現できますが、AWSのECSではできないのでこのようにConsulと組み合わせて構築する必要があります。