IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 3: OverlayネットワークとDocker SwarmとDocker ComposeでRethinkDBをスケールさせる

　[前回](http://qiita.com/masato/items/a047798e48ccc1e56eb8)までに作成したOverlayネットワークの[Docker Swarm](https://docs.docker.com/swarm/)クラスタへ[Docker Compose](https://docs.docker.com/compose/)を使い[RethinkDB](https://www.rethinkdb.com/)をデプロイしてみます。 RethinkDBの[ブログ](http://rethinkdb.com/blog/)は読んでいて楽しいので気に入っています。[ES6 Generator](http://rethinkdb.com/blog/rethinkdbdash-iojs/)のサポートも早くモダンなデータベースです。


## このシリーズ

* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 1: Overlayネットワークの作成](http://qiita.com/masato/items/6a1fa797b6c25d4c5745)
* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 2: Docker Swarmクラスタの作成](http://qiita.com/masato/items/a047798e48ccc1e56eb8)
* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 3: OverlayネットワークとDocker SwarmとDocker ComposeでRethinkDBをスケールさせる](http://qiita.com/masato/items/bd3d50b31f16a00eac47)
* [IDCFクラウドのDebian JessieでMulti-Host Docker Networking - Part 4: Couchbase Serverをスケールしてみる](http://qiita.com/masato/items/0be8b7da012f1180c281)

## 参考

　以下のサイトを参考にしました。

* [DockerでサクッとRethinkDBのクラスタを試す](http://qiita.com/lucidfrontier45/items/d006afbb4baea923a0c8)
* [Simplify deployment with the new networking features in Docker 1.9](https://www.rethinkdb.com/blog/docker-networking/)
* [Fun with Nuxeo Cloud and Docker Tools After DockerCon](http://www.nuxeo.com/blog/fun-with-nuxeo-cloud-and-docker-tools-after-dockercon/)



## 仮想マシン

　[前回](http://qiita.com/masato/items/a047798e48ccc1e56eb8)と同じ仮想マシンを使います。

|Dockerホストのhostname|Dockerホストのeth0| Docker Swarm |
|:--|:--|:--|
|minion-1|10.3.0.101| Swarm Manager/Agent |
|minion-2|10.3.0.102| Swarm Agent |
|minion-3|10.3.0.103| Swarm Agent |

## RethinkDB

　RethinkDBはオフィシャルの[イメージ](https://hub.docker.com/_/rethinkdb/)を使います。

### プロジェクト

　`rethink`の名前でディレクトリを作成して`docker-compose.yml`を配置します。このディレクトリ名はプロジェクト名としてコンテナの名前やOverlayネットワーク名として使われます。

```bash
$ tree .
.
└── rethink
    └── docker-compose.yml
```


## docker-compose.yml

　[DockerでサクッとRethinkDBのクラスタを試す](http://qiita.com/lucidfrontier45/items/d006afbb4baea923a0c8)を参考にして`docker-compose.yml`を作成します。

```yaml:docker-compose.yml
seed:
  image: rethinkdb:2
  ports:
    - "8088:8080"
  command: rethinkdb -n seed --bind all

worker:
  image: rethinkdb:2
  environment:
    - "affinity:container!=rethink_worker_*"
  command: rethinkdb --bind all -j rethink_seed_1:29015

proxy:
  image: rethinkdb:2
  ports:
    - "8080:8080"
  environment:
    - constraint:node==minion-3
  command: rethinkdb proxy --bind all -j rethink_seed_1:29015
```


　Docker Composeは[Releases](https://github.com/docker/compose/releases)サイトから最新バージョンをワンライナーでインストールします。

```bash
$ curl -L https://github.com/docker/compose/releases/download/1.5.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
```

### linksを使わない

　[Networking in Compose](https://docs.docker.com/compose/networking/)の[Links](https://docs.docker.com/compose/networking/#links)にあるように[libnetwork](https://github.com/docker/libnetwork)が導入され`links`はdeprecatedとなりました。`docker-compose.yml`から削除しています。

　これまでDocker Composeは`links`を指定するとコンテナの`/etc/hosts`に自動的にエントリーされ名前解決ができました。[libnetwork](https://github.com/docker/libnetwork)に対応してDocker Composeでは`--x-networking`フラグをつけて`up`するとプロジェクト名(ディレクトリ名)のネットワークが自動的に[docker network create](https://docs.docker.com/engine/reference/commandline/network_create/
)されます。`{ネットワーク名}_{サービス名}_N`のホスト名がコンテナの`/etc/hosts`に登録され名前解決ができるようになりました。


　ただしlibnetworkがまだエイリアスに対応していなかったり、`/etc/hosts`への登録にはいくつか問題がありissuesが上がっています。

* [About links at multi host x-networking](https://github.com/docker/compose/issues/2462)
* [simple names in /etc/hosts when using the experimental networking feature](https://github.com/docker/compose/issues/2312)

　[参考の例](http://qiita.com/lucidfrontier45/items/d006afbb4baea923a0c8)の`links`はサービス名で記述できましたが、`{ネットワーク名}_{サービス名}_N`のように固定にする必要があります。

```yaml
worker:
  image: rethinkdb:2
  links:
    - seed:seed
  command: rethinkdb --bind all -j seed:29015
proxy:
  image: rethinkdb:2
  ports:
    - 8080:8080
  links:
    - worker:worker
  command: rethinkdb proxy --bind all -j worker:29015
```

### Affinity filter

　`worker`サービスは[Affinity filter](https://docs.docker.com/swarm/scheduler/filter/#affinity-filter)を使い`anti-affinity`フィルターを作ります。`rethink_worker_*`のコンテナが起動していない別のノードを選びます。

```yaml
worker:
  image: rethinkdb:2
  environment:
    - "affinity:container!=rethink_worker_*"
  command: rethinkdb --bind all -j rethink_seed_1:29015
```

### Constraint filter

　`proxy`サービスは[Constraint Filter](https://docs.docker.com/swarm/scheduler/filter/#constraint-filter)を指定して`minion-3`のノードを特定して起動します。IDCFクラウドの設定でパブリックIPアドレスと`minion-3`をスタティックNATしています。

```yaml
proxy:
  image: rethinkdb:2
  ports:
    - "8080:8080"
  environment:
    - constraint:node==minion-3
  command: rethinkdb proxy --bind all -j rethink_seed_1:29015
```

## Docker SwarmとOverlayネットワーク

 `DOCKER_HOST`環境変数に`Swarm Manager`を設定してから`up`するとSwarmクラスタにデプロイします。

```basg
$ export DOCKER_HOST=tcp://10.3.0.101:3333
$ pwd
/root/rethink
$ docker-compose \
  --x-networking \
  --x-network-driver=overlay \
  up -d
```

 Dockerイメージがないノードでは`docker pull`するので少し時間がかかります。`docker-compose ps`で確認するとサービスのコンテナが1つずつ起動しました。


```bash
$ docker-compose ps
         Name                     Command                    State                     Ports
-----------------------------------------------------------------------------------------------------
rethink_proxy_1           rethinkdb proxy --bind    Up                        28015/tcp, 29015/tcp, 1
                          all ...                                             0.3.0.103:8080->8080/tc
                                                                              p
rethink_seed_1            rethinkdb -n seed         Up                        28015/tcp, 29015/tcp, 1
                          --bind all                                          0.3.0.101:8088->8080/tc
                                                                              p
rethink_worker_1          rethinkdb --bind all -j   Up                        28015/tcp, 29015/tcp,
                          re ...                                              8080/tcp
```

　`--x-networking`フラグを指定するとプロジェクト名でDockerネットワークを作成します。`rethink`ネットワークが作成されました。

```bash
$ docker network ls
NETWORK ID          NAME                DRIVER
3f8bacd30250        rethink             overlay
f10c0f7978af        dn                  overlay
b68b118036d2        bridge              bridge
636664a4f746        docker_gwbridge     bridge
6e0cf0387184        none                null
bc09b464b0c5        host                host
```

 Swarm Managerを指定して`docker ps`で確認すると`NAMES`列のコンテナ名は`{Dockerホスト名}/{ネットワーク名}_{サービス名}_N`のように付けられています。

```bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                             NAMES
b9f13b49004a        rethinkdb:2         "rethinkdb proxy --bi"   4 seconds ago       Up 2 seconds        28015/tcp, 10.3.0.103:8080->8080/tcp, 29015/tcp   minion-3/rethink_proxy_1
581d02852c24        rethinkdb:2         "rethinkdb --bind all"   5 seconds ago       Up 4 seconds        8080/tcp, 28015/tcp, 29015/tcp                    minion-2/rethink_worker_1
4ae146ed7671        rethinkdb:2         "rethinkdb -n seed --"   6 seconds ago       Up 5 seconds        28015/tcp, 29015/tcp, 10.3.0.101:8088->8080/tcp   minion-1/rethink_seed_1}}}
```
 
　`--x-network-driver=overlay`フラグはコンテナの`eth0`にOverlayネットワークを作成します。

```bash
$ docker exec minion-3/rethink_proxy_1 ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
134: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    link/ether 02:42:0a:00:00:04 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.4/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe00:4/64 scope link
       valid_lft forever preferred_lft forever
136: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe12:3/64 scope link
       valid_lft forever preferred_lft forever
```

　`/etc/hosts`にもOverlayネットワークに参加してホスト名が登録されているので、Dockerホストをまたいだ名前解決ができます。

```bash
$ docker exec minion-3/rethink_proxy_1 cat /etc/hosts
10.0.0.4        f704478aaadf
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.0.0.2        rethink_seed_1
10.0.0.2        rethink_seed_1.rethink
10.0.0.3        rethink_worker_1
10.0.0.3        rethink_worker_1.rethink
10.0.0.5        rethink_worker_2
10.0.0.5        rethink_worker_2.rethink
10.0.0.6        rethink_worker_3
10.0.0.6        rethink_worker_3.rethink
```


## scale

　`up`している状態で`worker`サービスのコンテナを3台にscaleします。

```bash
$ docker-compose \
  --x-networking \
  --x-network-driver=overlay \
  scale worker=3
Creating and starting 2 ... done
Creating and starting 3 ... done
```

　`anti-affinity`のフィルターを指定すると`worker`サービスのコンテナはなるべく同じDockerホスト上で起動しないようスケジュールされます。`worker=3`としてSwarmクラスタのノード数と合わせたので1つずつコンテナが起動しました。

```bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                                             NAMES
d6a1e40685f9        rethinkdb:2         "rethinkdb --bind all"   8 seconds ago       Up 7 seconds        8080/tcp, 28015/tcp, 29015/tcp                    minion-3/rethink_worker_3
4eb7c2959112        rethinkdb:2         "rethinkdb --bind all"   8 seconds ago       Up 7 seconds        8080/tcp, 28015/tcp, 29015/tcp                    minion-1/rethink_worker_2
b9f13b49004a        rethinkdb:2         "rethinkdb proxy --bi"   2 minutes ago       Up 2 minutes        28015/tcp, 10.3.0.103:8080->8080/tcp, 29015/tcp   minion-3/rethink_proxy_1
581d02852c24        rethinkdb:2         "rethinkdb --bind all"   2 minutes ago       Up 2 minutes        8080/tcp, 28015/tcp, 29015/tcp                    minion-2/rethink_worker_1
4ae146ed7671        rethinkdb:2         "rethinkdb -n seed --"   2 minutes ago       Up 2 minutes        28015/tcp, 29015/tcp, 10.3.0.101:8088->8080/tcp   minion-1/rethink_seed_1
```

### トラブルシュート

　`--x-networking`をつけないでscaleしたコンテナには`/etc/hosts`が入りません。scaleしたコンテナが同じDockerホストのコンテナも名前解決ができなくなり、少し嵌りました。

```bash
$ docker exec minion-3/rethink_worker_3 cat /etc/hosts
172.17.0.3      8df54f957347
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
```