CLOVER🍀

That was when it all began.

Consulでクラスタを構成、Service設定をしてみる

先日、WildFly Swarm+Consulでちょっと遊んでみたのですが、Consulのクラスタ構成がイマイチわかって
いなかったので、やり直しということで。

WildFly Swarm+Consul(+Dnsmasq)でService Discovery - CLOVER

今回は、ConsuleをSingle Nodeで、クラスタ構成する場合、あと設定ファイルを書くところをやって
みたいと思います。また、Consul Agentの動作モードにはServerとClientがありますがここでは
Serverを話題の中心に扱っています。

対象のConsulのバージョンは、0.7.2とします。

参考)
Consul は 全自動オーケストレーションの 夢を見るか?

Single NodeでConsulを使う

ここでいう「Single Node」とは、Server ModeのConsulです。Client側は置いておきます。

とりあえず、Single Nodeで雑に起動したい場合は「-bootstrap」を付与するのが正解みたいです。

$ ./consul agent -server -bootstrap -data-dir=/[data-directory]

もしくは、「-bootstrap-expect」を1に設定。

$ ./consul agent -server -bootstrap-expect=1 -data-dir=[data-directory]

Client側は、これにjoinすればOK。

$ ./consul agent -data-dir=[data-direcotry] -join=[server address]

Server側を起動する時に、「-bootstrap」もしくは「-bootstrap-expect」についてなにも考慮しないと

    2017/01/15 07:13:50 [ERR] agent: failed to sync remote state: No cluster leader

となり、そのままLeaderを探しつづけてうまく起動しません、と。

「-bootstrap-expect」を1にした場合は、1度この表記は出ますが、自身がLeaderになって起動します。

Configuration

「-bootstrap」オプションの意味ですが、やはりSingle Node向けの設定のようです。「-bootstrap-expect」は
起動時のクラスタ構成数となります。

Consul Agent(Server)でクラスタを構成する場合

次に、Consul Agent(Server)でクラスタを構成する場合を考えます。今回は、3 Nodeで構成してみます。

この場合、「-bootstrap-expect」は3となり、3 Node揃ったところでConsulクラスタが機能し始めることになります。

では、3つNodeを起動してみます。

## Node 1
$ ./consul agent -server -bootstrap-expect=3 -data-dir=[data-directory]

## Node 2
$ ./consul agent -server -bootstrap-expect=3 -data-dir=[data-directory] -join=[node 1 ip address]

## Node 3
$ ./consul agent -server -bootstrap-expect=3 -data-dir=[data-directory] -join=[node 1 ip address]

もしくは、

## Node 1
$ ./consul agent -server -bootstrap-expect=3 -data-dir=[data-directory]

## Node 2
$ ./consul agent -server -bootstrap-expect=3 -data-dir=[data-directory]

## Node 3
$ ./consul agent -server -bootstrap-expect=3 -data-dir=[data-directory]

とした後に、どこかのNodeでjoinします。

$ ./consul join [node 1 ip address] [node 2 ip address] [node 3 ip address]

ひとつのNodeを起点にでも全体がつながれば、クラスタを構成してくれます。

Consulでは、(ひとつのデータセンター内では)Serverの数が3または5が推奨で、Serverの起動数とQuorumの関係はこちらを参照するとよいでしょう。

Consensus / Deployment Table

Clientは、このクラスタにjoinすればOKです。

Quorumの確認をしてみる

先ほど、Deployment Tableについての参照を書きましたが、Nodeをダウンさせた時にどうなるのか、ちょっと確認してみましょう。

先ほどの3台構成の場合は、Quorumが2となり、1台のNode損失には耐えられるはずです。また、2台ダウンしてしまうとQuorumを
満たさなくなるので、その時にどうなるかというところですね。

このクラスタ構成にClientを加え、4 Nodeの状態でServer Nodeのひとつ(3番目)を落としてみます。

3つ目のServerの色が変わりました。

でも、ふつうに使えます。ここでさらに2番目のServer Nodeも落としてみます。

すると、Web UIにアクセスできなくなってしまいました。

ログ上はQuorumを満たさなくなったことが出力され、Leaderをロストしたことになっています。

    2017/01/15 13:30:03 [WARN] raft: Failed to contact quorum of nodes, stepping down
    2017/01/15 13:30:03 [INFO] raft: Node at 172.17.0.2:8300 [Follower] entering Follower state (Leader: "")
    2017/01/15 13:30:03 [INFO] consul: cluster leadership lost

そして、Leaderが定まらない状態になります。

    2017/01/15 13:30:17 [ERR] agent: coordinate update error: No cluster leader

この時、まったくConsulが使えなくなるかというと、そんなことはなさそうです。

DNSの機能も動いていますし、

$ dig @127.0.0.1 -p 8600 consulserver1.node.consul ANY

; <<>> DiG 9.9.5-3ubuntu0.11-Ubuntu <<>> @172.17.0.2 -p 8600 consulserver1.node.consul ANY
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29386
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;consulserver1.node.consul.	IN	ANY

;; ANSWER SECTION:
consulserver1.node.consul. 0	IN	A	172.17.0.2

;; Query time: 0 msec
;; SERVER: 172.17.0.2#8600(172.17.0.2)
;; WHEN: Sun Jan 15 22:41:48 JST 2017
;; MSG SIZE  rcvd: 59

Client側のHTTP APIも使えます。

$ curl http://localhost:8500/v1/agent/members
[{"Name":"consulclient","Addr":"172.17.0.5","Port":8301,"Tags":{"build":"0.7.2:'a9afa0c","dc":"dc1","role":"node","vsn":"2","vsn_max":"3","vsn_min":"2"},"Status":1,"ProtocolMin":1,"ProtocolMax":5,"ProtocolCur":2,"DelegateMin":2,"DelegateMax":4,"DelegateCur":4},{"Name":"consulserver2","Addr":"172.17.0.3","Port":8301,"Tags":{"build":"0.7.2:'a9afa0c","dc":"dc1","expect":"3","port":"8300","role":"consul","vsn":"2","vsn_max":"3","vsn_min":"2"},"Status":4,"ProtocolMin":1,"ProtocolMax":5,"ProtocolCur":2,"DelegateMin":2,"DelegateMax":4,"DelegateCur":4},{"Name":"consulserver3","Addr":"172.17.0.4","Port":8301,"Tags":{"build":"0.7.2:'a9afa0c","dc":"dc1","expect":"3","port":"8300","role":"consul","vsn":"2","vsn_max":"3","vsn_min":"2"},"Status":4,"ProtocolMin":1,"ProtocolMax":5,"ProtocolCur":2,"DelegateMin":2,"DelegateMax":4,"DelegateCur":4},{"Name":"consulserver1","Addr":"172.17.0.2","Port":8301,"Tags":{"build":"0.7.2:'a9afa0c","dc":"dc1","expect":"3","port":"8300","role":"consul","vsn":"2","vsn_max":"3","vsn_min":"2"},"Status":1,"ProtocolMin":1,"ProtocolMax":5,"ProtocolCur":2,"DelegateMin":2,"DelegateMax":4,"DelegateCur":4}]

このあとで新しいClientを追加してみたら、一応joinはしていそうな雰囲気になりました。

が、クラスタとしては不正な状態になっていることは変わりなさそうです。ここで、落としていたServer Nodeを起動すると
Leaderが再選出されます。

    2017/01/15 13:43:25 [INFO] consul: New leader elected: consulserver1

まだ1 Node欠けたままですが、クラスタの状態としては回復し、Web UIでもアクセス可能になります。

Consulの設定をしてみる

と、ここまでクラスタ構成についての確認をしてきました。とはいえ、起動引数に何度も書くのも微妙なので、このあたりを
設定ファイルに書きたいと思います。

Consulの設定ファイルは、JSON形式で書きます。

設定ファイルの書き方は、こちらを参照するとよいでしょう。

Configuration / Configuration Files

Server側

Server側は、今回こんな感じで作ってみました。
server.json

{
  "bootstrap_expect": 3,
  "data_dir": "[data-directory]",
  "server": true,
  "start_join": [
      "node 1 ip adress", "node 1 ip adress", "node 1 ip adress"
  ]
}

意味は、コマンドラインのオプションで指定していたものとほとんど同じです。

これで起動する場合は、以下のようなオプション指定になります。

$ ./consul agent -config-file=server.json

これで、先ほどと同様3 Node起動すれば、Consul Agnet(Server)でのクラスタが構成されます。

Client側

続いて、クライアント側。設定ファイルの書き方自体はServerと同じですが、こちらにはServiceも加えてみましょう。

加えるServiceは、Apachehttpd)とします。
※Client側には、Apacheがインストールされているものとします

Clientの設定とServiceの設定を同じ設定ファイルに書いてもいいのですが、今回は分割してみます。

client.json

{
  "data_dir": "[data-directory]",
  "start_join": [
      "node 1 ip adress", "node 1 ip adress", "node 1 ip adress"
  ]
}

ApacheのService設定。
service-httpd.json

{
  "service": {
    "name": "httpd",
    "tags": ["http"],
    "address": "",
    "port": 80,
    "checks": [
      {
        "script": "curl http://localhost >/dev/null 2>&1",
        "interval": "10s"
      }
    ]
  }
}

Health Checkは、10秒ごとにトップページに対してアクセスします。

この状態で、設定ファイルを置いたディレクトリを「-config-dir」オプションで指定して起動します。

$ ./consul agent -config-dir=[設定ファイルを置いたディレクトリ]

「-config-dir」で指定したディレクトリ内の、「.json」拡張子のファイルを読み込んでくれます。

Web UIで確認してみましょう。

Web UIを使う場合は、設定ファイルに以下の設定が必要です。外部ホストから接続する場合は、「client_addr」も。

  "ui": true

Serviceを認識してくれています。

Health Checkも入れているので、Apacheを落とすと

$ sudo service apache2 stop

Health CheckでNGとなります。

Apacheを再度起動すると、復帰します。

$ sudo service apache2 start

また、今回はひとつのファイルに単一のService定義をしましたが、複数記述することもできるようです。

Services / Multiple Service Definitions

ファイルを分割するか、一気に書くかはお好みといったところで。

まとめ

Consulのクラスタ構成に関する「-bootstrap」および「-bootstrap-expect」、それから設定ファイルの書き方といったところを見てみました。

クラスタのところは、前回ちょっともやもやしていたので、これですっきりしましたね。