Consul入門
Consulとかいうツールが流行っているようだが結局何ができるかよくわからなかったのでここを斜め読みして軽くまとめる。
ここではあえてAtlasについては触れない。
ちなみにTerraformについては以下に書いた。
Consulの特長。
- Service Discovery
- サービスの発見(サービス検出)
- サービスとは何等かのWebサービスやデータベースといった高レベルのサービスのこと
- Helth Checking
- 上記のサービス検出と併せて、そのサービスが動作していること(HTTP Status 200 OKとか)やメモリ使用率のチェックができる
- ヘルスチェックというか「監視」のイメージ(個人的な感想)
- Key/Value Store
- Consul Agent間でkey-valueデータを共有・保持できる
- Multi Datacenter
- 別ネットワークとも連携が可能
- DRように別々のデータセンター間でもConsul Agent同士は連携できる
Consulでは各ノードにConsul Agentを配備し、そのノード(自分自身)のヘルスチェックを行う。
ConsulはSerfの上位に位置する。
(Serfが持つgossip protocolを使用するという意味で。基本別モノ。)
Serfとは?
SerfもまたHashicorp社のツールで、gossip protocolを使用し、Membership(クラスタ構成)、故障検出、イベントのブロードキャストの機能を提供する。
Serfでは各ノードにAgentが存在し、gossip protocolでUDP通信による無作為なコミュニケーションを実施する。
AgentにはServer AgentとClient Agentがある。
gossip protocolにはLAN Gossip(LAN・データセンタ内)とWAN Gossip(LAN・データセンタ間、ただしServer Agentのみ)がある。
イメージについてはここを参照。
Serfで実現するクラスタ構成や故障検出は、Serf Agentの生存如何で実現する。
Consulが高レベルなヘルスチェック(サービスレベル)ができるとすると、Serfは低レベルなヘルスチェックという表現になる。
ConsulもまたSerfと同様、クラスタ構成を取る。
インストール
ここからプラットフォームに合ったバイナリを落とす。 zipなので好きなところに展開する。
1つ実行ファイルが出てくるのでPATHを通す。
コマンドで「consul」をたたいて動くかどうか確認する。
# DOA C:\tools\consul_0.5.2>consul usage: consul [--version] [--help] <command> [<args>] Available commands are: agent Runs a Consul agent configtest Validate config file event Fire a new event exec Executes a command on Consul nodes force-leave Forces a member of the cluster to enter the "left" state info Provides debugging information for operators join Tell Consul agent to join cluster keygen Generates a new encryption key keyring Manages gossip layer encryption keys leave Gracefully leaves the Consul cluster and shuts down lock Execute a command holding a lock maint Controls node or service maintenance mode members Lists the members of a Consul cluster monitor Stream logs from a Consul agent reload Triggers the agent to reload configuration files version Prints the Consul version watch Watch for changes in Consul
Starting the Agent
Consul Agentはサーバモードかクライアントモードで実行できる。
Multi Datacenterで実行する場合、各データセンタ(LAN)には少なくとも1つ以上のConsul Serverが必要で、
1つのデータセンタ(LAN)には3~5ノードのConsul Serverが存在することが推奨される。
(Consul Serverが1ノードだと、障害時にデータロスするかもしれない)
Consul Agentをサーバモードで起動するには「 consul agent -server」コマンドを使用する。
# sh $ consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul ==> WARNING: BootstrapExpect Mode is specified as 1; this is the same as Bootstrap mode. ==> WARNING: Bootstrap mode enabled! Do not enable unless necessary ==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1 ==> Starting Consul agent... ==> Starting Consul agent RPC... ==> Consul agent running! Node name: 'Armons-MacBook-Air' Datacenter: 'dc1' Server: true (bootstrap: true) Client Addr: 127.0.0.1 (HTTP: 8500, DNS: 8600, RPC: 8400) Cluster Addr: 10.1.10.38 (LAN: 8301, WAN: 8302) ==> Log data will now stream in as it occurs: [INFO] serf: EventMemberJoin: Armons-MacBook-Air.local 10.1.10.38 [INFO] raft: Node at 10.1.10.38:8300 [Follower] entering Follower state [INFO] consul: adding server for datacenter: dc1, addr: 10.1.10.38:8300 [ERR] agent: failed to sync remote state: rpc error: No cluster leader [WARN] raft: Heartbeat timeout reached, starting election [INFO] raft: Node at 10.1.10.38:8300 [Candidate] entering Candidate state [INFO] raft: Election won. Tally: 1 [INFO] raft: Node at 10.1.10.38:8300 [Leader] entering Leader state [INFO] consul: cluster leadership acquired [INFO] consul: New leader elected: Armons-MacBook-Air [INFO] consul: member 'Armons-MacBook-Air' joined, marking health alive
「Ctrl + C」で正常終了する。
Cluster Members
別DOS/ターミナルを開いて「consul members」コマンドを実行するとクラスタ内のノード一覧が出力される。
# sh $ consul members Node Address Status Type Build Protocol Armons-MacBook-Air 10.1.10.38:8301 alive server 0.5.1 2
ConsulはHTTP APIも提供しており、下記のようにAPI経由でクラスタ内のノード一覧を取得できる。
# sh $ curl localhost:8500/v1/catalog/nodes [{"Node":"Armons-MacBook-Air","Address":"10.1.10.38"}]
さらにDNS APIも提供しており、下記のようにクラスタ内のノード一覧を取得できる。
# sh $ dig @127.0.0.1 -p 8600 Armons-MacBook-Air.node.consul ... ;; QUESTION SECTION: ;Armons-MacBook-Air.node.consul. IN A ;; ANSWER SECTION: Armons-MacBook-Air.node.consul. 0 IN A 10.1.10.38
Defining a Service
Consulではサービスの定義をJSONで行う。
JSONファイルの保存先は「consul.d」ディレクトリ配下。
ここでは、「/etc/consul.d」とする。
# sh $ sudo mkdir /etc/consul.d
サービスの定義はJSONの「service」要素で指定する。
ポート80番のWebサーバサービスを定義する場合は下記のようになる。
# sh $ echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' \ >/etc/consul.d/web.json
サービス定義の詳細についてはここを参照。
上記で作成したディレクトリを指定してConsul Agentを再起動する。
# sh $ consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul \ -config-dir /etc/consul.d ==> Starting Consul agent... ... [INFO] agent: Synced service 'web' ...
Syncedと出てればサービス定義がロードされている。
また、「SIGHUP」シグナルをConsul Agentプロセスへ投げると、再起動しなくても設定ファイルを再ロードしてくれる。
DNS API
ひとたびサービスを登録するとDNS API経由で確認できる。
サービス名は「NAME.service.consul」で定義され、NAMEの部分は自分で設定したサービス名になる。(サブドメインは変更できる)
今回はサービス定義のJSONのname要素で「web」というサービス名を指定している。
# sh $ dig @127.0.0.1 -p 8600 web.service.consul ... ;; QUESTION SECTION: ;web.service.consul. IN A ;; ANSWER SECTION: web.service.consul. 0 IN A 172.20.20.11
アドレスやポート情報を全て表示したい場合は「SRV」を付ける。
# sh $ dig @127.0.0.1 -p 8600 web.service.consul SRV ... ;; QUESTION SECTION: ;web.service.consul. IN SRV ;; ANSWER SECTION: web.service.consul. 0 IN SRV 1 1 80 agent-one.node.dc1.consul. ;; ADDITIONAL SECTION: agent-one.node.dc1.consul. 0 IN A 172.20.20.11
また、タグにより出力結果をフィルタリングできる。
今回はサービス定義のJSONのtags要素で「rails」というタグを指定している。
# sh $ dig @127.0.0.1 -p 8600 rails.web.service.consul ... ;; QUESTION SECTION: ;rails.web.service.consul. IN A ;; ANSWER SECTION: rails.web.service.consul. 0 IN A 172.20.20.11
HTTP API
DNS APIだけでなくHTTP APIでもサービスの確認ができる。
# sh $ curl http://localhost:8500/v1/catalog/service/web [{"Node":"agent-one","Address":"172.20.20.11","ServiceID":"web", \ "ServiceName":"web","ServiceTags":["rails"],"ServicePort":80}]
Joining a Cluster
ここでは
* ホスト名:n1、IP:172.20.20.10
* ホスト名:n2、IP:172.20.20.11
の2台のサーバ(Vagrantで起動)がいる前提で書く。
まず、n1にログインしてagent-oneというノード名をつけてConsul Agentを起動する。
# sh $ vagrant ssh n1 vagrant@n1:~$ consul agent -server -bootstrap-expect 1 \ -data-dir /tmp/consul -node=agent-one -bind=172.20.20.10 ...
そして、n2にログインしてagent-twoというノード名をつけてConsul Agentを起動する。
# sh $ vagrant ssh n2 vagrant@n2:~$ consul agent -data-dir /tmp/consul -node=agent-two \ -bind=172.20.20.11 ...
この状態で新規にターミナルを起動してn1にログインし、「consul join」コマンドでn2を指定してクラスタに参加する。
# sh vagrant@n1:~$ consul join 172.20.20.11 Successfully joined cluster by contacting 1 nodes.
ターミナルを起動してn2にログインし、「consul members」コマンドでクラスタノード一覧を表示するとクラスタに参加できていることがわかる。
# sh vagrant@n2:~$ consul members Node Address Status Type Build Protocol agent-two 172.20.20.11:8301 alive client 0.5.0 2 agent-one 172.20.20.10:8301 alive server 0.5.0 2
「Ctrl + C」でクラスタから正常に離脱し、Consul Agentも正常に停止する。
DNS APIを使用してノードの情報を取得する際、「NAME.node.consul」や「NAME.node.DATACENTER.consul」のNAMEの部分にConsul Agent起動時に「-node」オプションで指定したノード名を使用することができる。
# sh vagrant@n1:~$ dig @127.0.0.1 -p 8600 agent-two.node.consul ... ;; QUESTION SECTION: ;agent-two.node.consul. IN A ;; ANSWER SECTION: agent-two.node.consul. 0 IN A 172.20.20.11
Defining Checks
ヘルスチェックの定義はJSONの「check」要素で指定する。
# sh vagrant@n2:~$ echo '{"check": {"name": "ping", \ "script": "ping -c1 google.com >/dev/null", "interval": "30s"}}' \ >/etc/consul.d/ping.json vagrant@n2:~$ echo '{"service": {"name": "web", "tags": ["rails"], "port": 80,\ "check": {"script": "curl localhost >/dev/null 2>&1", "interval": "10s"}}}' \ >/etc/consul.d/web.json
ここでは
* google.comへのpingを30秒間隔
* localhostへのcurlを10秒間隔
のヘルスチェックをscriptで定義している。
Consul AgentへSIGHUPシグナルを投げて設定を再ロードすると、Consul Agentを起動したターミナルに下記の内容が標準出力される。
==> Starting Consul agent... ... [INFO] agent: Synced service 'web' [INFO] agent: Synced check 'service:web' [INFO] agent: Synced check 'ping' [WARN] Check 'service:web' is now critical
今回は「web」のサービスを起動していないので、「critical」と表示されていて、サービスのヘルスチェックがNGであることがわかる。
Checking Health Status
HTTP APIでサービスのステータスを確認する。
今回は、ステータスが「critical」のものを取得する。
# sh vagrant@n1:~$ curl http://localhost:8500/v1/health/state/critical [{"Node":"agent-two","CheckID":"service:web","Name":"Service 'web' check","Status":"critical","Notes":"","ServiceID":"web","ServiceName":"web"}]
Consul設定ファイルの再ロードの際と同様、「web」サービスがcriticalとして取得できていることがわかる。
また、DNS APIで確認すると、結果が取得できない、つまりヘルスチェックNGであることがわかる。
# sh dig @127.0.0.1 -p 8600 web.service.consul ... ;; QUESTION SECTION: ;web.service.consul. IN A
Key-Value Store
ConsulはKey-Value Storeを持つ。
動的な設定変更、サービス調整の補助等に使用できる。
Key-Value StoreはHTTP APIで提供されている。
まずは取得してみる。
# sh $ curl -v http://localhost:8500/v1/kv/?recurse * About to connect() to localhost port 8500 (#0) * Trying 127.0.0.1... connected > GET /v1/kv/?recurse HTTP/1.1 > User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3 > Host: localhost:8500 > Accept: */* > < HTTP/1.1 404 Not Found < X-Consul-Index: 1 < Date: Fri, 11 Apr 2014 02:10:28 GMT < Content-Length: 0 < Content-Type: text/plain; charset=utf-8 < * Connection #0 to host localhost left intact * Closing connection #0
今回は何も保存していないので404となった。
PUTメソッドでキーkey1、key2、key3に3通りの方法で値testを設定してみる。
# sh $ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key1 true $ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key2?flags=42 true $ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/sub/key3 true $ curl http://localhost:8500/v1/kv/?recurse [{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="}, {"CreateIndex":98,"ModifyIndex":98,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="}, {"CreateIndex":99,"ModifyIndex":99,"Key":"web/sub/key3","Flags":0,"Value":"dGVzdA=="}]
ここで注意なのは、値はbase64エンコードされているということ。
また、「?recurse」パラメータを付けると全てのKey-Valueペアが取得できるが、下記のように単一のキーを指定することもできる。
# sh $ curl http://localhost:8500/v1/kv/web/key1 [{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="}]
DELETEメソッドで削除することができる。
# sh $ curl -X DELETE http://localhost:8500/v1/kv/web/sub?recurse $ curl http://localhost:8500/v1/kv/web?recurse [{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="}, {"CreateIndex":98,"ModifyIndex":98,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="}]
「?recurse」を付けると指定した階層の全てのKey-Valueペアを削除することができる。
また更新の際は、PUTメソッドで且つ「?cas=」パラメータに更新対象の「ModifyIndex」を指定することで更新できる。
# sh $ curl -X PUT -d 'newval' http://localhost:8500/v1/kv/web/key1?cas=97 true $ curl -X PUT -d 'newval' http://localhost:8500/v1/kv/web/key1?cas=97 false
上記でわかるように、更新すると「ModifyIndex」の値は変更される。
この更新時にModifyIndexが変更される仕組みを使って、GET時に値が変更されるまで待ってから取得する機能がある。
# sh $ curl "http://localhost:8500/v1/kv/web/key2?index=101&wait=5s" [{"CreateIndex":98,"ModifyIndex":101,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="}]
「?index=」パラメータを使用すると、ModifyIndexが指定した値以上になるまで待ってから値を取得してくれる。
また、「?wait=5s」を指定すると、最大で5秒しか待たない、という意味になる。
WEB UI
ここからWEB UI用のパッケージをダウンロードしてConsul Agentをインストールしたマシンのどこかに解凍する。
Consul Agentを再起動して、「-ui-dir」パラメータでUIを解凍したパスを指定する。
# sh $ consul agent -ui-dir /path/to/ui ...
UIはHTTP APIと同じポートの「/ui」パスで見ることができる。
デフォルトは「http://localhost:8500/ui」。
デモページはここ。