公式のDockerイメージからConsulを起動して遊ぶ

# はじめに

オライリーの [Docker](https://www.amazon.co.jp/gp/product/4873117763/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4873117763&linkCode=as2&tag=nakamine11-22&linkId=d621d4ccac6e586f8ee835ef6ef33230) を読んで、 Consul を触ってみたかったが、
書籍の出版から時間が経っていて、書籍のとおりに環境構築できなかった。
公式ページのドキュメンテーションを見ながら構築したときの備忘録。


# 構成の概要

* [HashiCorp社の公式Dockerイメージ](https://hub.docker.com/r/_/consul/) を使う。
* Digital Ocean に 2 台ノードを用意。 Docker Machine でコンテナをデプロイする。
  * consul-1
  * consul-2
* 本来のConsulの運用では奇数台用意するが、今回はConsulの動作を確認したいだけなので2台にする
* [公式イメージのドキュメント](https://hub.docker.com/r/_/consul/)の記述に乗っ取って、コンテナを起動するときに `-net=nost` オプションを指定している。こうすることでホストマシンのインターフェースから直接コンテナのインターフェースとやりとりできるので、オーバーヘッドが少なく、高速に動作する。
* DNSサービスはデフォルトの5300番ポートでなく、53番ポートを使う

# 環境構築

## 仮想マシンの起動

DigitalOcean上に仮想マシンを2台起動する。

```:ローカルPC
$ docker-machine create --driver=digitalocean --digital-ocean-access-token xxxxxxx consul-1
$ docker-machine create --driver=digitalocean --digital-ocean-access-token xxxxxxx consul-2
```

## Consulサーバエージェントの起動

consul-1 と consul-2 のそれぞれに consul コンテナを起動する。

ノードのIPは何回か参照するので環境変数に設定しておく。

```:ローカルPC
$ HOSTA=$(docker-machine ip consul-1)
$ HOSTB=$(docker-machine ip consul-2)
```

consul-1 にConsulサーバエージェントを起動。

```:consul-1
$ eval $(docker-machine env consul-1)
$ docker run -d \
  --name=consul \
  --net=host \
  -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
  -e 'CONSUL_ALLOW_PRIVILEGED_PORTS=' \
  consul:1.2.2 agent -server \
    -bind=$HOSTA \
    -advertise=$HOSTA \
    -dns-port=53 \
    -recursor=8.8.8.8 \
    -client=0.0.0.0 \
    -retry-join=$HOSTB \
    -bootstrap-expect=2
```

consul-2 にConsulサーバエージェントを起動。

```:consul-2
$ eval $(docker-machine env consul-2)
$ docker run -d \
  --name=consul \
  --net=host \
  -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
  -e 'CONSUL_ALLOW_PRIVILEGED_PORTS=' \
  consul:1.2.2 agent -server  \
    -bind=$HOSTB \
    -advertise=$HOSTB \
    -dns-port=53 \
    -recursor=8.8.8.8 \
    -client=0.0.0.0 \
    -retry-join=$HOSTA \
    -bootstrap-expect=2
```

クラスターのメンバーにサーバエージェントが2つ起動していることを確認。

```:consul-1,consul-2
$ docker exec consul consul members
Node      Address               Status  Type    Build  Protocol  DC   Segment
consul-1  x.x.x.x:8301  alive   server  1.2.2  2         dc1  <all>
consul-2  x.x.x.x:8301     alive   server  1.2.2  2         dc1  <all>
```

これで環境構築完了。

# Consulで遊んでみる

## サービスを登録してみる

ConsulにRedisサービスの情報を登録する。

consul-2にredisを起動。

```:consul-2
$ eval $(docker-machine env consul-2)
$ docker run -d -p 6379:6379 --name redis redis:4
```

redisサービスをconsulに登録する。

```:consul-1
$ curl -XPUT http://$HOSTA:8500/v1/agent/service/register -d \
  '{"name":"redis","address":"'$HOSTB'","port":6379}'
```

`redis.service.consul` で名前解決できるようになる。

```:consul-1
$ dig @$HOSTA SRV +short redis.service.consul
1 1 6379 8e5d41c2.addr.dc1.consul.
```

## ヘルスチェックを設定してみる

アプリケーションのヘルスチェックの設定をする。

### サービスの起動

dnmonster サービスを起動する。

```:consul-1
$ docker run --net=host \
             --dns=$HOSTA \
             --dns-search=service.consul -d \
             --name dnmonster amouat/dnmonster:1.0
```

### サービスの登録

* ヘルスチェックの監視周期を10秒に指定する

```:consul-1
curl -XPUT http://$HOSTA:8500/v1/agent/service/register --data @dnmonster.json
```

```json:dnmonster.json
{
  "name":"dnmonster", 
  "address":"(consul-1のIPアドレス)", 
  "port":8080, 
  "check": { 
    "http": "http://(consul-1のIPアドレス):8080/monster/foo", 
    "interval":"10s"
  }
}
```


### サービス停止を検知するかの確認

dnmosneter サービスを停止する

```:consul-1
$ docker stop dnmonster
```

consul のログにエラーが出る。

```:consul-1
$ docker logs -f consul
...
2018/08/11 08:18:11 [WARN] agent: Check "service:dnmonster" HTTP request failed: Get http://x.x.x.x:8080/monster/foo: dial tcp x.x.x.x:8080: connect: connection refused
```

# 参考

* [Docker（書籍）](https://www.amazon.co.jp/gp/product/4873117763/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4873117763&linkCode=as2&tag=nakamine11-22&linkId=d621d4ccac6e586f8ee835ef6ef33230)
* [ConsulのDocker公式イメージ](https://hub.docker.com/r/_/consul/)
* [HashiCorpの公式ドキュメント](https://www.consul.io/docs/guides/consul-containers.html)