GORBとConsulで，お気楽L4ロードバランス

[別記事](http://qiita.com/monamour555/items/2e7441de89a4b7df9ccb)で，Docker クラスタのロードバランスを容易に実現する GORB を紹介しました．
記事中で， GORB には単体で使うとクラッシュ時のデータの永続性が無いという致命的な問題があること，これを克服するため，Consul を用いることができると書きました．

内部ロードバランサとして用いる想定で，実際に設定してみました．

環境
====

3ノードの CoreOS です．全てのノードで LVS は有効にしてあります．
IP forwarding と LVS が有効になっていれば，他の Linux 系ディストリビューションでも同様と思います．
それぞれのノードのホスト名は `node0`, `node1`, `node2` とします．
全ての作業は node0 上で行っています．

Consul クラスタの立ち上げ
=======================

Consul の詳細はここでは省略し，作業手順だけ記します．

Bootstrap マスタ
-----

Consul の各ノードにマスタ/スレーブはありませんが，ブートストラップ時だけはマスタが必要です．まずはマスタを立ち上げます．

```shell-session
node0$ docker run -d --restart=always --net=host --name consul progrium/consul -server -bootstrap-expect 3
```

残りの各ノード
------------

続いて各ノードを，マスタを向くようにして立ち上げます．
今回は 3 ノードなので 2 ノードです．

```shell-session
node0$ ssh node1 docker run -d --restart=always --net=host --name consul progrium/consul -server -join node0
$ ssh node2 docker run -d --restart=always --net=host --name consul progrium/consul -server -join node0
```

`-join` の引数に IP アドレスを明示している記事も見かけますが，名前解決を適切に設定してあれば，ホスト名(ここでは node0)でも良いようです．

確認
----

すぐにクラスタリングは完了します．

```shell-session
$ curl http://localhost:8500/v1/catalog/nodes
[{"Node":"node0","Address":"10.0.0.6"},{"Node":"node1","Address":"10.0.0.4"},{"Node":"node2","Address":"10.0.0.5"}]
```

それぞれのIPアドレスで問い合わせても，当然同じ値が返ります．

```shell-session
$ curl http://10.0.0.4:8500/v1/catalog/nodes
[{"Node":"node0","Address":"10.0.0.6"},{"Node":"node1","Address":"10.0.0.4"},{"Node":"node2","Address":"10.0.0.5"}]
```

```shell-session
$ curl http://10.0.0.5:8500/v1/catalog/nodes
[{"Node":"node0","Address":"10.0.0.6"},{"Node":"node1","Address":"10.0.0.4"},{"Node":"node2","Address":"10.0.0.5"}]
```

```shell-session
$ curl http://10.0.0.6:8500/v1/catalog/nodes
[{"Node":"node0","Address":"10.0.0.6"},{"Node":"node1","Address":"10.0.0.4"},{"Node":"node2","Address":"10.0.0.5"}]
```

GORB
=====

GORB の詳細は[別記事](http://qiita.com/monamour555/items/2e7441de89a4b7df9ccb)を参照してください．

gorb のデプロイ
-------------

gorb はどこで起動してもよいですが，今回はクラスタの内部バランサとして使うという想定で，node0 に立ち上げます．

```
docker run -d --restart=always --name gorb --net=host --privileged monami0ya/gorb -f -i eth0 -c http://localhost:8500/
```

ここで Consul Web API への URL を localhost にするのがコツです．
既述の通り，クラスタ内のどのホストからでも取得可能ではありますが，別のホストを参照すると，そのホストが落ちている時には Consul の更新ができなくなります．
gorb と Consul は別のコンテナなので，Consul コンテナが落ちる可能性はありますが，他のホストを見に行くよりはリスクが低くなります．

gorb-link のデプロイ
------------------

続いて，全てのノードに gorb-link をデプロイします．

```shell-session
node0$ docker run --restart=always -d --net=host -v /var/run/docker.sock:/var/run/docker.sock --name gorb-link monami0ya/gorb-docker-link -r node0:4672 -i eth0
node0$ ssh node1 docker run --restart=always -d --net=host -v /var/run/docker.sock:/var/run/docker.sock --name gorb-link monami0ya/gorb-docker-link -r node0:4672 -i eth0
node0$ ssh node2 docker run --restart=always -d --net=host -v /var/run/docker.sock:/var/run/docker.sock --name gorb-link monami0ya/gorb-docker-link -r node0:4672 -i eth0
```

動作確認
--------

gorb により Consul に登録されたサービス一覧を確認してみます．

```
node0$ curl http://localhost:8500/v1/agent/services
```

おつかれさま，完了です．

痒いところ
=========

いちど構築してしまえば，**ほぼ**メンテナンスフリーで，とても楽です．
しかし，痒いところも残っています．

フェイルオーバしてくれない
----------------------

gorb コンテナが死んだとき，フェイルオーバはしてくれません．
しかし，Consul が動作しているので，いかようにもなるとは言えます．

gorb 自身を Consul にサービス登録しない
-----------------------------------

どういうわけか gorb は Consul に自分自身の Web API をサービスとして登録しません．
サービス登録があれば，Consul の DNS インタフェースを使って，gorb が動作しているホストの IP アドレスを簡単に割り出せます．
そうなればフェイルオーバの実現も楽になると思うのですが…．この件は暇を見つけてプルリクを投げ<del>ようと思っています</del>ました．[最新のソースツリーではマージされています](https://github.com/kobolog/gorb/commit/2d8df455dbfdebce4d4965bac249020b8d0417cd)。