別記事で,Docker クラスタのロードバランスを容易に実現する GORB を紹介しました.
記事中で, GORB には単体で使うとクラッシュ時のデータの永続性が無いという致命的な問題があること,これを克服するため,Consul を用いることができると書きました.
内部ロードバランサとして用いる想定で,実際に設定してみました.
環境
3ノードの CoreOS です.全てのノードで LVS は有効にしてあります.
IP forwarding と LVS が有効になっていれば,他の Linux 系ディストリビューションでも同様と思います.
それぞれのノードのホスト名は node0
, node1
, node2
とします.
全ての作業は node0 上で行っています.
Consul クラスタの立ち上げ
Consul の詳細はここでは省略し,作業手順だけ記します.
Bootstrap マスタ
Consul の各ノードにマスタ/スレーブはありませんが,ブートストラップ時だけはマスタが必要です.まずはマスタを立ち上げます.
node0$ docker run -d --restart=always --net=host --name consul progrium/consul -server -bootstrap-expect 3
残りの各ノード
続いて各ノードを,マスタを向くようにして立ち上げます.
今回は 3 ノードなので 2 ノードです.
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)でも良いようです.
確認
すぐにクラスタリングは完了します.
$ 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アドレスで問い合わせても,当然同じ値が返ります.
$ 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"}]
$ 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"}]
$ 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 の詳細は別記事を参照してください.
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 をデプロイします.
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 アドレスを簡単に割り出せます.
そうなればフェイルオーバの実現も楽になると思うのですが….この件は暇を見つけてプルリクを投げようと思っていますました.最新のソースツリーではマージされています。