前回に引き続き、Consul 関連ドキュメント ( http://consul.io/ ) の参考訳です。
内容は、Consul エージェントについて、DNS インターフェース、HTTP API、service と check の定義について。
■ CONSUL エージェント
http://www.consul.io/docs/agent/basics.html
Consul エージェントは、Consul の中核となるプロセスです。エージェントはメンバーシップ情報を保持し、サービス情報の登録や、チェックの実行、クエリに対する回答や、その他の動作をします。Consul クラスタに含まれる全てのノードで、このノードを動作させなくてはいけません。
エージェントは、クライアントかサーバか、いずれかの状態で動作します。サーバノードでは、クォーラム・コンセンサス(総意)形成の一部となるため、追加の義務を引き受けます。これらノードは Raft を形成し、障害発生における強い一貫性と可用性を担保します。サーバノードに対する重い負担から、サーバノードは専用インスタンス上で動作させる事を意味しており、通常、クライアントノードよりもリソースを多く割り当てるべきでしょう。クラスタの大部分を占めるのはクライアントノードですが、非常に軽量で、メンテナンスにほとんど手が掛かりません。また、多くの操作はサーバノードを通して行います。
Running an Agent / エージェントの起動
Consul を起動するには ‘consul agent’ と実行します。コマンドを実行すると、エージェントは停止させるまで実行し続けます。エージェントコマンドには様々な設定オプションがありますが、通常はデフォルトのままでも十分でしょう。’consul agnet’ を実行すると、以下の様に表示されます。
$ consul agent -data-dir=/tmp/consul ==> Starting Consul agent... ==> Starting Consul agent RPC... ==> Consul agent running! Node name: 'Armons-MacBook-Air' Datacenter: 'dc1' Server: false (bootstrap: false) Client Addr: 127.0.0.1 (HTTP: 8500, DNS: 8600, RPC: 8400) Cluster Addr: 192.168.1.43 (LAN: 8301, WAN: 8302) ==> Log data will now stream in as it occurs: [INFO] serf: EventMemberJoin: Armons-MacBook-Air.local 192.168.1.43 ...
‘consul agent’ の出力にあたって、いくつかの重要な要素があります。
- ‘Node name:’ ノード名。エージェント固有の名称です。デフォルトではマシンのホスト名ですが、’-node’ フラグを用いて、任意のホスト名称に変更出来ます。
- ‘Datacenter‘: データセンタ。エージェントが実行する際に設定するデータセンタの指定です。Consul は複数のデータセンタで利用できるよう第一級のサポートを行いますが、効率的に働くためには、各々のノードがどのデータセンタで動作しているかを明示しなくてはいけません。’-dc’ フラグは、データセンタを指定するために使用します。データセンタを1つしか使用しない場合のため、デフォルトでは “dc1” に設定されます。
- ‘Server‘:サーバ。エージェントがサーバとして動作しているか、あるいはクライアント・モードで動作しているかを明示します。サーバノードは、総意形成やクラスタ状態の保存、クエリの取り扱いのために重い負担を持っています。また、サーバは “ブートストラップ”モードに指定する場合もあります。最初のサーバは、追加サーバがクラスタへの参加を許可できるよう、このモードにしなくてはいけません。一方で、複数のサーバがブートストラップ・モードになることは、クラスタ状態が矛盾するため、ありえません。
- ‘Client Addr‘:エージェントがクライアント用のインターフェースに使用する IP アドレスです。ここで指定する IP アドレスは、HTTP や DNS および RPC インターフェースの為のポート番号も含みます。RPC 用のアドレスは、他の ‘consul’ コマンドから使用するために用います。’consul members’ など他の Consul から実行中エージェントに対するコマンドは、エージェントに接続したり、問い合わせや制御を行うために RPC を用います。デフォルトでは、ローカルホストをバインドします(127.0.0.1 が割り当てられます)。IP アドレスやポート番号を変更したい場合は、’-rpc-addr’ を用いて指定した後、’consul members’ など問い合わせをさせたいエージェントに対して、あらかじめ知らせておく必要があります。また、これは他のアプリケーションが RPC を通して Consul を制御できることを意味します。
- ‘Cluster Addr:’クラスタ上で Consul エージェント間が通信をする際に使用する IP アドレスとポート番号を指定します。クラスタ上すべての Consul エージェントが同じポートを使用する必要はありませんが、他のノードから到達可能な IP アドレスであることが「必須」です。
Stopping an Agent / エージェントの停止
エージェントは gracefully(グレースフル/上品に) または focefully(強制的に) いずれかで停止します。
graceful にエージェントを停止(halt)させるためには、プロセスに対する割り込みシグナル、通常はターミナル上で ‘Ctrl+C’ を実行します。停止が graceful な場合、まず、エージェントはクラスタに対してクラスタを離脱しようとする事を通知します。そのため、他のクラスタ・メンバーは、対照ノードが’去った'(left)という通知を受け取ります。
あるいは、kill シグナルを送信することで強制的にエージェントを停止させることもできます。強制的に停止させようとすると、エージェントは直ちに停止します。クラスタの残りのメンバは、しばらくの後(通常は数秒以内)ノードが停止した事を検出し、クラスタ全体に対し、ノードで障害が発生した(failed)と通知します。
とりわけ重要なのは、コンセンサス・クォーラムからサーバが離れた時の影響を最小限に抑えるため、サーバノードを gracefully に離脱させることです。
一方、クライアントエージェントの場合、ノードで障害が発生したか、あるいはノードから離脱したかの間に、さほど大きな違いはありません。たとえば、ウェブサーバとロードバランサのセットアップをするにあたり、ロードバランサのプールからウェブノードを削除するような事と同じ程度なのです。ですが、状況によっては、(fail時とleft時では)別々の対応を行うかもしれません。
■ DNS インターフェース
http://www.consul.io/docs/agent/dns.html
Cosul の重要なクエリ・インターフェースの1つは DNS を用いています。DNS インターフェースは、アプリケーションによるサービス検出を、Consul と直接やりとりする事なく行うために重要なものです。たとえば、Consul に対して HTTP API を通してリクエストを行う代わりに、そのホスト DNS サーバを直接利用し、”redis.service.east-aws.consul” のようなホスト名の名前解決が可能です。
このクエリは、「east-aws」データセンタにある「redis」というサービスを保持するノードの名前解決を自動的に行います。ここで得られたホスト情報には、ノードが落ちているかどうか、ヘルスチェックの必要はありません(正常なノードの情報しか返さないため)。非常にシンプルです!
DNS インターフェースには、いくつかの重要な設定オプションがあります。’dns_addr’ と ‘recursor’ 、そして ‘domain’ です。デフォルトでは、Consul は 127.0.0.1:8600 を「consul.」ドメインの DNS クエリのために使用します。”consul.” ドメインには、DNS 再帰問い合わせの機能はありません。
DNS インターフェースには、いくつかの使い方があります。使い方の1つは、カスタムした DNS リゾルバライブラリを用いて、参照先を Consul に向けることです。あるいは、Consul を DNS サーバのノードとすることで、Consul クラスタに含まれていないクエリに対する再帰問い合わせにも用いることが出来ます。他には、既存の DNS サーバから Consul エージェントに対して、’consul.’ ドメインに関する名前解決に用いる方法があります。コマンドラインで DNS サーバに問い合わせるには、dig コマンドを用います:
$ dig @127.0.0.1 -p 8600 redis.service.dc1.consul. ANY
Node Lookups / ノードの名前解決
Consul が名前解決を行うためには、特定の形式のクエリに依存します。基本的には、ノード確認(node lookups)とサービス確認(service lookups)の2つのクエリです。ノード確認は、ノード名称に対する IP アドレスを問い合わせるシンプルなクエリで、書式は次のようになります。
<node>.node.<datacenter>.<domain>
では、たとえば「foo」という名前のノードがあるなら、デフォルトでは「foo.node.dc1.consul.」となります。FQDN におけるデータセンタ名はオプション指定しますが、明示しない場合は、エージェントのデフォルトのデータセンタが指定されます。さて、もし「foo」が同じデータセンタで動作している事が分かっている場合は「foo.node.consul.」も使用することができます。同じデータセンタだけでなく、他のデータセンタ上のノードに対する DNS の名前解決も、追加設定なく、同様に行う事ができます。 ノードの確認にあたって、唯一返ってくるのはノードの IP アドレスにあたる A レコードです。
$ dig @127.0.0.1 -p 8600 foobar.node.consul ANY ; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 foobar.node.consul ANY ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24355 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;foobar.node.consul. IN ANY ;; ANSWER SECTION: foobar.node.consul. 0 IN A 10.1.10.12 ;; AUTHORITY SECTION: consul. 0 IN SOA ns.consul. postmaster.consul. 1392836399 3600 600 86400 0
Service Lookup / サービス確認
サービス確認は、別の種類のクエリです。サービスプロバイダ(HTTP サーバなど)に対するクエリとして用います。サービス確認のための書式は、次のようになります。
<tag>.<service>.service.<datacenter>.<domain>
ノードの確認と同様に、データセンタ名(datacenter)はオプションです。タグ(tag)も同様にオプションです。タグの指定が無ければ、タグに対するフィルタリングは行われません。たとえば、ローカルのデータセンタ上で何らかの redis サービスを提供するノードを特定したい場合、「redis.service.consul.」によって知ることができます。ですが、PostgreSQL のマスタに関してはこれでは分かりませんので、その場合は「master.postgresql.service.dc2.consul.」のような確認ができます。
DNS クエリ・システムは、障害の発生しているノードに対するルーティング(誘導)を避けるため、ヘルスチェック情報を用います。サービスに対するクエリが発生したとき、ノードのあらゆるサービスのヘルスチェックが正常か障害かチェックされ、問題があった場合はクエリ結果から除外されます。単純なロードバランシングを行うため、ノードのセットがある場合、結果は毎回ランダムに返されます。この単純な仕組みによって、アプリケーションレベルで自動修復アーキテクチャの簡単な基盤 ( auto-healing service oriented architecture ) として、簡単に DNS を用いる事ができるようになります。
A レコードと SRV レコードが名前解決の為に提供されます。SRV レコードはポート番号を伝える役割もあります。これは、サービスが一般的なポート番号(well-known port)に依存しないようにするため、サービスによって登録されます。SRV レコードは、クライアントが SRV レコードの要求を明示した時だけ提供されます。
$ dig @127.0.0.1 -p 8600 consul.service.consul SRV ; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 consul.service.consul ANY ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50483 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;consul.service.consul. IN SRV ;; ANSWER SECTION: consul.service.consul. 0 IN SRV 1 1 8300 foobar.node.dc1.consul. ;; ADDITIONAL SECTION: foobar.node.dc1.consul. 0 IN A 10.1.10.12
■HTTP API
http://www.consul.io/docs/agent/http.html
Consul の主要インターフェースは RESTful な HTTP API です。API は、node ( ノード ) や service ( サービス ) や check ( チェック )、configuration ( 設定 )に対する CRUD (Create 生成, Read 読み取り, Update 更新, Delte 削除)のために使用できます。API のエンドポイントは、下位互換性を壊す事無く変更できるよう、バージョン管理を行います。
エンドポイントは5つのカテゴリに分類されます。
- kv – キーバリュー・ストア
- agent – エージェント制御
- catalog – ノードやサービスの管理
- health – ヘルスチェックの管理
- status – Consul のシステム状態
各々のカテゴリと、それらエンドポイントに関する文章は以下をお読みください。
Blocking Queries / ブロッキング・クエリ
特定のエンドポイントは「blocking query」と呼ばれる機能を持ちます。blocking query(ブロック・クエリ) は、長時間のポーリング(応答待ち)が発生するかもしれない場合の、待ち時間のために用います。クエリがこの機能を使うためには、利用時に明示する必要がありますが、これを使うかどうかは自由です。機能を使いたい場合は、問い合わせ時の HTTP ヘッダに「X-Consul-Index」を用います。クライアントがこれを使うかどうかは、分かりません(オプションです)。
クエリのブロックを使いたいときは、リクエスト時のクエリのパラメータに「”?wait=<間隔>&index=<インデックス名>”」を追加します。
「?wait=」クエリ・パラメータは、どれだけクエリをブロックするか(塞ぐか/阻むか)を指定します。指定が無い場合、デフォルトは 10 分です。指定するには「10s」(10秒)や「5m」(5分)のような形式にします。「?index=」パラメータは、Consul が変更を検出するための、不明瞭なハンドル(操作)です。クエリが「X-Consul-Index」ヘッダを持つ場合には、クエリが実行されてから変更が発生するまで待機するために用いることができます。
指定があると、変更があるまで Consul は応答することをブロック(遮る)するので、出力に変化があった時には、インデックスに対する何らかの動きがあることを意味します。重要な注意として、このクエリが、変更後いつ返ってくるかの「保証はありません」。つまり、タイムアウトに達した可能性もありますし、結果が返ってくるのと同時に発生したとは限らないのです。
KV
KV エンドポイントは簡単なキーバリュー・ストアを公開するために用います。ストアサービスは、簡単な方法でサービス設定や、他のメタデータを保管するために使用できます。
エンドポイントは1つだけです。
/v1/kv/<key>
ここがキーバリュー・ストアにおける唯一のエンドポイントです。ここでは HTTP のメソッドに依存します。GET 、PUT、DELETE メソッドは全てサポートされています。重要なのは、各々のデータセンタで各々のキーバリュー・ストアを持つので、データセンタ間でレプリケーション(複製)することはできません。デフォルトでは、特に指定がなければ自分自身のデータセンタ内を参照しますが、「?dc=」クエリパラメータを用いることで、他のデータセンタに問い合わせることができます。もし全てのデータセンタに対して書き込みを行いたいなら、データセンタ毎にリクエストを生成する必要があります。
GET’ メソッドを使う場合、Consul は特定のキーに対する値を返すか、「?recurse」クエリパラメータが追加されたときは、指定したキー名を含むすべての値を返します。
これらは以下の様に参照できます。
[ { "CreateIndex":100, "ModifyIndex":200, "Key":"zip", "Flags":0, "Value":"dGVzdA==" } ]
‘ModifyIndex’ は、エントリに変更が加わった時を示すインデックス値です。ここで扱うインデクス値というのは、’X-Consul-Index’ ヘッダで指定した値と一致します。ブロッキングクエリは、値の変更がu発生するのを待つために使用できます。もし「?recurse」が使われた場合は、’X-Consul-Index’ は、’ModifyIndex’ の最新値と一致するまで、対照となるキーに対する更新が掛かるまでブロッキングクエリは待機します。
‘Key’ は、単純にエントリのフルパスで表します。’Flags’ は、各々のエントリに対して付与されるかもしれない(符号の無い)整数です。これらを用いるかどうかは、ユーザに任せられています。なお、これら ‘value’ は base64 をキー(base64 でエンコード)とする値です。
エントリが見つからない場合は、404 コードが返されます。
‘PUT’ メソッドを用いる場合、Consul はリクエスト body が、一致するキーに対する値であろうとみなします。PUT リクエストで利用することのできるパラメータは複数あります。
- ?flags=<num> : ここで指定できるのは 0 ~ 2^64-1 までの符号の無い値です。ユーザは使わないかもしれませんが、クライアント・アプリケーションによっては使うかもしれません。
- ?cas=<index> : このフラグは ‘PUT ‘ で「Check-And-Set」操作のために用います。クライアントが複雑な同期処理を構成する際には、便利なものとなるでしょう。インデックスが 0 の場合、Consul は存在しない key に値を入れるだけです。もし 0 ではないインデックスの場合、key が ‘ModifyIndex’ と一致する場合だけ値をセットします。
戻り値は ‘true’ か ‘false’ かという、シンプルなものです。CAS チェックが失敗する時は、’false’ を返します。
最後に ‘DELETE’ メソッドは、対照となる1つのキーか、prefix (接頭区、文字の一部)を共有する全てのキーを削除することができます。”?recurse” クエリパラメータが指定された場合は、一致するキー名称だけでなく、prefix が一致するものを全て削除します。
Agent / エージェント
Agent エンドポイントは、ローカルの Consul エージェントと連携するために用います。通常、エージェントによって service と check がカタログに登録され、アンチエントロピー(元の状態に戻ろうとする性質)のために、障害発生から復旧するまでの性能向上という役割を持ちます。msgpack RPC プロトコルを用いるかわりに、様々な API が提供されています。
以下のエンドポイントがサポートされています。
- /v1/agent/checks: ローカルエージェントが管理している check を返す
- /v1/agent/services : ローカルエージェントが管理している service を返す
- /v1/agent/members : ローカル serf エージェントが見えているメンバを返す
- /v1/agent/join/<address> : ローカルエージェントがノードに join するトリガ
- /v1/agent/force-leave/<node>: ノードを force remove(強制削除)
- /v1/agent/check/register : 新しいローカル check の登録
- /v1/agent/check/pass/<checkID> : ローカルテストを通過(passing)したとマーク
- /v1/agent/check/warn/<checkID> : ローカルテストの警告(warning)をマーク
- /v1/agent/check/fail/<checkID> : ローカルテストの障害(critical)をマーク
- /v1/agent/service/register : 新しいローカル service の登録
- /v1/agent/service/deregister/<serviceID> : ローカル service の削除
/v1/agent/checks
ローカルエージェントで登録された全ての check を返すエンドポイントとして用います。ここでの checks は設定ファイルで明示されるか、 HTTP API を用いて動的に追加されたものです。重要な注意点として、エージェントによって知られている checks と、Catalog によって報告さるものは違う事があります。とはいえ、通常はリーダーが選出されていない間のみです。エージェントはアンチ・エントロピーとして(状態が収束するように)動作しますので、ほとんどの状況では、情報は数秒以内に同期します。
このエンドポイントを GET でたたくと、次のような JSON body を返します。
{ "service:redis":{ "Node":"foobar", "CheckID":"service:redis", "Name":"Service 'redis' check", "Status":"passing", "Notes":"", "ServiceID":"redis", "ServiceName":"redis" } }
/v1/agent/services
ローカルエージェントで登録された全ての service を返すエンドポイントとして用います。ここでの services は設定ファイルで明示されるか、 HTTP API を用いて動的に追加されたものです。重要な注意点として、エージェントによって知られている services と、Catalog によって報告さるものは違う事があります。とはいえ、通常はリーダーが選出されていない間のみです。エージェントはアンチ・エントロピーとして(状態が収束するように)動作しますので、ほとんどの状況では、情報は数秒以内に同期します。
このエンドポイントを GET でたたくと、次のような JSON body を返します。
{ "redis":{ "ID":"redis", "Service":"redis", "Tags":null, "Port":8000 } }
/v1/agent/memers
このエンドポイントを GET でたたくと、クラスタの Gossip プール上でエージェントが見えているメンバを返します。Gossip の結果整合性(eventual consistency) という(最終的に情報が一致する)性質上、問い合わせ結果はエージェントによって異なる場合があります。強一貫性を持つ(絶対的に正しい)ノードの一覧を取得する場合には、「/v1/catalog/nodes」を使います。
サーバモードでエージェントが動作している場合、「?wan=1」クエリパラメータを使うと、デフォルトの LAN メンバを含む、WAN メンバのリストを返します。
エンドポイントが返す JSON body は次の通りです。
[ { "Name":"foobar", "Addr":"10.1.10.12", "Port":8301, "Tags":{ "bootstrap":"1", "dc":"dc1", "port":"8300", "role":"consul" }, "Status":1, "ProtocolMin":1, "ProtocolMax":2, "ProtocolCur":2, "DelegateMin":1, "DelegateMax":3, "DelegateCur":3 } ]
/v1/agent/join/<address>
エンドボイントに GET でアクセスがあると、エージェントに対して指定した IP アドレスに対して接続するよう命じます。サーバモードでエージェントが動作している場合、「?wan=1」クエリパラメータを使うと、WAN プールに join しようとします。
join に成功すると、エンドポイントが 200 を返します。
/v1/agent/force-leave/<node>
エンドポイントに GET でアクセスがあると、エージェントに対して指定したノードを切り離す(left)よう命じます。ノードが想定外のエラー(または失敗)を起こす場合は “failed” の状態にします。この ‘failed’ 状態になると、Consul は対照ノード再接続を試み、それまで対象ノードに属する services や checks は正常になりません。’left’ 状態になったノードの古い情報は、全て削除されます。
このエンドポイントでは、常に 200 を返します。
/v1/agent/check/register
register エンドポイントでは、ローカルエージェントに対して新しい check を追加するために用います。check については、より詳しい文章がこちらにあります。check はスクリプトか TTL 型です。エージェントは check のステータスを管理し、 Catalog が同期し続けるようにする役割があります。
登録済みのエンドポイントに対するリクエストは JSON リクエストで body を PUT します。リクエスト body は次のような形式にしなくてはいけません。
{ "ID": "mem", "Name": "Memory utilization", "Notes": "Ensure we don't oversubscribe memory", "Script": "/usr/local/bin/check_mem.py", "Interval": "10s", "TTL": "15s" }
‘Name’ フィールドは必須です。’Script’ と ‘Interval’ か、’TTL’ も必須です。’Script’ と ‘Interval’ か、’TTL’ いずれか一つが指定されます。’ID’ が指定されないときは、’Name’ の値がセットされます。エージェント毎に ‘ID’ エントリを重複持たせることができないので、各々の ID を決める必要があります。Consul は ‘Notes’ フィールドを使用しませんが、人間にとっては読めるものになるでしょう。
‘script’ が指定された場合、check タイプは script となり、Consul は指定した ‘Interval'(間隔) の度に評価を行い status を更新します。’TTL’ 型が用いられた場合、API は定期的に 対象 check に対する status を更新しなければいけません。
戻りコードが 200 の場合は成功です。
/v1/agent/check/deregister/<checkId>
deregister エンドポイントは、ローカルエージェントから対象の check を登録削除します。CheckID はスラッシュの後で明示しなくてはいけません。エージェントは Catalog から情報を削除するように動作します。
戻りコードが 200 の場合は成功です。
/v1/agent/check/pass/<checkId>
このエンドポイントは TTL 型の check の時に用います。エンドポイントに対してアクセスがあると、対象となる check に対する status を “passing” (合格/正常) とし、TTL クロックをリセットします。
戻りコードが 200 の場合は成功です。
/v1/agent/check/warn/<checkId>
このエンドポイントは TTL 型の check の時に用います。エンドポイントに対してアクセスがあると、対象となる check に対する status を “warning” (警告) とし、TTL クロックをリセットします。
戻りコードが 200 の場合は成功です。
/v1/agent/check/fail/<checkId>
このエンドポイントは TTL 型の check の時に用います。エンドポイントに対してアクセスがあると、対象となる check に対する status を “critical” (致命的) とし、TTL クロックをリセットします。
戻りコードが 200 の場合は成功です。
/v1/agent/service/register
register エンドポイントでは、ローカルエージェントに対して新しい service を追加するために用います。service については、より詳しい文章がこちらにあります。service はヘルスチェックも提供します。エージェントは service のステータスを管理し、 Catalog が同期し続けるようにする役割があります。
登録済みのエンドポイントに対するリクエストは JSON リクエストで body を PUT します。リクエスト body は次のような形式にしなくてはいけません。
{ "ID": "redis1", "Name": "redis", "Tags": ["master", "v1"], "Port": 8000, "Check": { "Script": "/usr/local/bin/check_redis.py", "Interval": "10s", "TTL": "15s" } }
‘Name’ フィールドは必須です。’ID’ が指定されないときは、’Name’ の値がセットされます。エージェント毎に ‘ID’ エントリを重複持たせることができないので、各々の ID を決める必要があります。’Tags’、’Port’、’check’ はオプションです。もし ‘check’ が指定されるのは、’Script’ と ‘Interval’ 、または ‘TTL’ が用いられるときのみです。詳細な情報はこちらを参照下さい。
作成された check は “service:<サービスID>” 形式の名称となります。
戻り値が 200 の場合は成功です。
/v1/agent/service/deregister/<serviceId>
deregister エンドポイントは、ローカルエージェントから対象の service を登録削除します。ServiceID はスラッシュの後で明示しなくてはいけません。エージェントは Catalog から情報を削除するように動作します。
戻りコードが 200 の場合は成功です。
Catalog
Catalog は、node や service および checks の登録と、登録解除のためエンドポイントです。また、いくつかのクエリ・エンドポイントも提供します。
次のようなエンドポイントが提供されます。
- /v1/catalog/register : 新しい node、service、check の登録
- /v1/catalog/datacenters : 既知のデータセンタ一覧
- /v1/catalog/nodes : 指定したデータセンタ上に存在するノード一覧
- /v1/catalog/services : 指定したデータセンタ上に存在するサービス一覧
- /v1/catalog/service/<service> : 指定したサービスが存在するノード一覧
- /v1/catalog/node/<node> : 指定したノード上のサービス一覧
最後の4つのカタログに対するエンドポイントは、ブロッキング・クエリをサポートします。
/v1/catalog/register/
register エンドポイントは、指定した catalog に対して直接登録するためのローレベルな仕組みです。一般的に、エージェントのローカルエンドポイントを、簡単かつアンチ・エントロピーのために使う事を推奨されます。
register エンドポイントの JSON リクエスト body は PUT で行われます。リクエスト body は以下の様になります。
{ "Datacenter": "dc1", "Node": "foobar", "Address": "192.168.10.10", "Service": { "ID": "redis1", "Service": "redis", "Tags": ["master", "v1"], "Port": 8000, }, "Check": { "Node": "foobar", "CheckID": "service:redis1", "Name": "Redis health check", "Notes": "Script based health check", "Status": "passing", "ServiceID": "redis1" } }
エンドポイントの動作は、どのようなキーが提供されるかに依存します。データセンタがエージェントのものと一致する場合、エンドポイントには ‘Node’ と ‘Address’ が必要になります。これらが指定されさえすれば、catalog にノードが登録されます。
‘Service’ キーが指定されると、service も同様に登録されます。’ID’ が指定されない場合は、’Service’ が割り当てられます。ID は一意なノードを示すように(ユニークに)管理する必要があります。’Tags’ と ‘Port’ は省略可能です。
‘Check’ キーが提供される場合は、ヘルスチェックも登録されます。重要なのは、この register API は非常にローレベルだということです。ここではヘルスチェックのエントリを操作しますが、スクリプトや status を実際に更新する TTL の調整は行いません。この動作のため、エージェントのローカルチェックは別途設定されるべきです。
‘CheckID’ は省略可能ですが、その場合は ‘Name’ が使用されます。そのため、’CheckID’ はユニークなものにしなければいけません。’Notes’ は人間読み込み可能な文字列を意味するオプション項目です。’ServiceID’ がノード上にある service の ID と一致する場合、その check は、ノードレベルのヘルスチェックではなく、サービスレベルのヘルスチェックとみなされます。また、status は “unknown”、”passing”、”warning”、”critical” のいずれかでなくてはいけませんん。”unknown” ( 未知 ) のステータスは、初回 check が未実行であることを示すために用います。
重要な注意として、’check’ は ‘service’ によって提供される必要はありませんし、その逆も然りです。提供することもできますが、省略するのも自由です。
API コールが成功すると、ステータスコードは 200 を返します。
/v1/catalog/deregister
deregister エンドポイントは、catalog から直接エントリを削除うsるための、ローレベルな仕組みです。一般的に、エージェントのローカルエンドポイントを、簡単かつアンチ・エントロピーのために使う事を推奨されます。
register エンドポイントの JSON リクエスト body は PUT で行われます。リクエスト body は以下の様になります。
{ "Datacenter": "dc1", "Node": "foobar", } { "Datacenter": "dc1", "Node": "foobar", "CheckID": "service:redis1" } { "Datacenter": "dc1", "Node": "foobar", "ServiceID": "redis1", }
エンドポイントの動作は、どのようなキーが提供されるかに依存します。データセンタがエージェントのものと一致する場合、エンドポイントには ‘Node’ が必要になります。’Node’ だけを指定する場合は、関連づけられている service と chek 全てが削除されます。’CheckID’ を指定するときは、所属するノードのみを削除します。’ServiceID’ を指定するときは、ヘルスチェック(存在する場合)が関連づけられている serice が削除されます。
API コールが成功すると、ステータスコードは 200 を返します。
/v1/catalog/datacenters
このエンドポイントに GET でアクセスすると、Consul サーバが既知のデータセンタを返します。
次のような JSON body を返します。
["dc1", "dc2"]
のエンドポイントは、クラスタのリーダである必要がないため、可用性が無い状態でもリクエストは成功します。したがって、Consul サーバに到達可能かどうか、簡単に確認するために使えます。
/v1/catalog/nodes
このエンドポイントに GET でアクセスすると、指定したデータセンタで既知のノードを返します。デフォルトで問い合わせ時にデータセンタを明示する必要はありませんが、”?dc=” クエリパラメータでデータセンタを指定することもできます。
次のような JSON body を返します。
[ { "Node":"baz", "Address":"10.1.10.11" }, { "Node":"foobar", "Address":"10.1.10.12" } ]
このエンドポイントは、ブロッキング・クエリをサポートします。
/v1/catalog/services
このエンドポイントに GET でアクセスすると、指定したデータセンタで既知の service を返します。デフォルトでは、エージェントがデータセンタを問い合わせるので指定の必要はありませんが、”?dc=” クエリパラメータでデータセンタを指定することもできます。
次のような JOSN body が戻ってきます。
{ "consul":[], "redis":[], "postgresql":["master","slave"] }
主なオブジェクト・キーはサービス名称で、指定したサービスに対する既知の tag を array で返します。
このエンドポイントは、ブロッキング・クエリをサポートします。
/v1/catalog/service/<service>
このエンドポイントに GET でアクセスすると、指定したデータセンタ上で、指定したサービスにを提供するノードを返します。デフォルトで問い合わせ時にエージェントの動作するデータセンタを明示する必要があります。”?dc=” クエリパラメータでデータセンタを指定することもできます。
問い合わせ対象の service は、スラッシュの後で明示する必要があります。デフォルトでは service を持っている全てのノードを返します。クエリパラメータに “?tag=” を付ける事で、結果をフィルタすることができます。
次のような JSON body を返します。
[ { "Node":"foobar", "Address":"10.1.10.12", "ServiceID":"redis", "ServiceName":"redis", "ServiceTags":null, "ServicePort":8000 } ]
このエンドポイントは、ブロッキング・クエリをサポートします。
/v1/catalog/node/<node>
このエンドポイントに GET でアクセスすると、指定したノードが提供する service を返します。デフォルトでは、エージェントがデータセンタを問い合わせるので指定の必要はありませんが、データセンタの指定は “?dc=” クエリパラメータと用いることができます。問い合わせ対象の node は、スラッシュの後で明示する必要があります。
次のような JSON body を返します。
{ "Node":{ "Node":"foobar", "Address":"10.1.10.12" }, "Services":{ "consul":{ "ID":"consul", "Service":"consul", "Tags":null, "Port":8300 }, "redis":{ "ID":"redis", "Service":"redis", "Tags":["v1"], "Port":8000 } } }
このエンドポイントは、ブロッキング・クエリをサポートします。
Health
Health は、ヘルス状態に関連する問い合わせの際に使用します。ユーザによっては、ヘルスチェックの仕組みは必要ありませんので、オプションとして返るよう、Catalog とは別の機能として提供されています。また、Catalog エンドポイントでは、ヘルスシステムによって、いくつかのクエリがフィルタされることがあります。
以下のエンドポイントがサポートされます。
- /v1/health/node/<node>: ノードのヘルス情報を返す
- /v1/health/checks/<service>: service のヘルス情報に関する check を返す
- /v1/health/service/<service>: service を持つノードのヘルス情報を返す
- /v1/health/state/<state>: 指定した state 状態にある check を返す
全てのヘルスエンドポイントは、ブロッキング・クエリをサポートします。
/v1/health/node/<node>
エンドポイントに GET でアクセスすると、指定した node 上で既知の check を返します。デフォルトでは、エージェントがデータセンタを問い合わせるので指定の必要はありませんが、”?dc=” クエリ・パラメータを使ってデータセンタを明示できます。対象ノードをスラッシュの後で明示する必要があります。
次のような JSON body を返します。
[ { "Node":"foobar", "CheckID":"serfHealth", "Name":"Serf Health Status", "Status":"passing", "Notes":"", "ServiceID":"", "ServiceName":"" }, { "Node":"foobar", "CheckID":"service:redis", "Name":"Service 'redis' check", "Status":"passing", "Notes":"", "ServiceID":"redis", "ServiceName":"redis" } ]
この例では、システムレベルでの check (Resis 向けのサービスチェックだけでなく、ServiceID には関係ないものも全て)を確認できます。”serfHealth” という名前の check は特別で、全てのノードは自動的にこの check を保持します。ノードが Consul クラスタに参加している間、ここは Serf によって提供される分散障害検知の一部として働きます。ノードが fail すると、この status は自動的に “critical”(致命的) に変化します。
このエンドポイントは、ブロッキングクエリをサポートします。
/v1/health/checks/<service>
エンドポイントに GET でアクセスすると、指定したデータセンタ上の service に関連する check を返します。デフォルトでは、エージェントがデータセンタを問い合わせるので指定の必要はありませんが、”?dc=” クエリ・パラメータを使ってデータセンタを明示できます。対象 service をスラッシュの後で明示する必要があります。
次のような JSON body を返します。
[ { "Node":"foobar", "CheckID":"service:redis", "Name":"Service 'redis' check", "Status":"passing", "Notes":"", "ServiceID":"redis", "ServiceName":"redis" } ]
このエンドポイントは、ブロッキングクエリをサポートします。
/v1/health/service/<service>
エンドポイントに GET でアクセスすると、指定したデータセンタ上の service node を返します。デフォルトでは、エージェントがデータセンタを問い合わせるので指定の必要はありませんが、”?dc=” クエリ・パラメータを使ってデータセンタを明示できます。
対象 service をスラッシュの後で明示する必要があります。デフォルトでは、全てのノード上の service を返します。しかし、”?tag=” クエリ・パラメータを使用してリストをフィルタすることが出来ます。
これは /v1/catalog/service エンドポイントと非常に似ていますが、このエンドポイントはd自動的に関連したヘルスチェックの status も返します。そこには、あらゆるシステムレベルのヘルスチェックも含みます。この機能によって、クライアント側は、ノードのヘルステストが失敗しているかや、どこで警告が出ているかのために、トラフィックを発生するのを避けることができます。
利用者は、この機能を動的なロードバランシングのために用いることが出来ますし、ヘルスチェックを用いる他の機能のためにも利用出来ます。
次のような JSON body を返します。
[ { "Node":{ "Node":"foobar", "Address":"10.1.10.12" }, "Service":{ "ID":"redis", "Service":"redis", "Tags":null, "Port":8000 }, "Checks":[ { "Node":"foobar", "CheckID":"service:redis", "Name":"Service 'redis' check", "Status":"passing", "Notes":"", "ServiceID":"redis", "ServiceName":"redis" },{ "Node":"foobar", "CheckID":"serfHealth", "Name":"Serf Health Status", "Status":"passing", "Notes":"", "ServiceID":"", "ServiceName":"" } ] } ]
このエンドポイントは、ブロッキングクエリをサポートします。
/v1/health/state/<state>
エンドポイントに GET でアクセスすると、指定したデータセンタの check を返します。デフォルトでは、エージェントがデータセンタを問い合わせるので指定の必要はありませんが、”?dc=” クエリ・パラメータを使ってデータセンタを明示できます。
対象 state をスラッシュの後で明示する必要があります。state としてサポートされているのは、”unknwon”、”passing”、”warning”、”critical” です。
次のような JSON body を返します。
[ { "Node":"foobar", "CheckID":"serfHealth", "Name":"Serf Health Status", "Status":"passing", "Notes":"", "ServiceID":"", "ServiceName":"" }, { "Node":"foobar", "CheckID":"service:redis", "Name":"Service 'redis' check", "Status":"passing", "Notes":"", "ServiceID":"redis", "ServiceName":"redis" } ]
このエンドポイントは、ブロッキングクエリをサポートします。
Status
status エンドポイントは Consul クラスタの状態に関する情報を取得するために用います。これらは非常にローレベルで、クライアントにとって、あまり役立つものではありません。
以下のエンドポイントが提供されています。
- /v1/status/leader : 現在の Raft リーダを返します。
- /v1/status/peers : 現在の Raft ピアの一覧を返します。
/v1/status/leader
このエンドポイントは、エージェントが動作しているデータセンタの Raft リーダを返します。次のようにアドレスを示します。
"10.1.10.12:8300"
/v1/status/peers
このエンドポイントは、エージェントが動作しているデータセンタの Raft ピア一覧を返します。次のようにアドレスを示します。
["10.1.10.12:8300", "10.1.10.11:8300", "10.1.10.10:8300"]
■ Service Definition / サービス定義
http://www.consul.io/docs/agent/services.html
サービス検出の主な目的の1つに、利用可能なサービスの catalog を提供する事です。そのために、エージェントは、利用可能な service を明示するための、簡単なサービスを定義するための書式を提供しています。また、これらはヘルスチェックと関連づけることができます。service を結びつけて考えると、ヘルスチェックとはアプリケーション層のものであると考えられます。service は設定ファイルで定義するか、稼働中はHTTP インターフェースを経由して追加します。
Service Definition / サービス定義
サービス定義は、以下の様なスクリプトによって行います。
{ "service": { "name": "redis", "tags": ["master"], "port": 8000, "check": { "script": "/usr/local/bin/check_redis.py", "interval": "10s" } } }
サービス定義では、’name’ を含むのが必須ですが、’id’、’tags’、’port’、’check’ はオプションで登録します。’id’ が指定されない場合は、’name’ のものが割り当てられます。全ての servie はユニークな ID を持つ必要があるので、name の名前は重複しないよう、ユニークな ID を割り振るべきです。
‘tags’ は Consul にとってはオプションとなるリストですが、ノードが “master” か “slave” かであるかや、バージョンの違いや、その他サービスレベルでのラベルとして用いることができます。’port’ は、サービス指向アーキテクチャのように設定するために用います。このようにして service の IP アドレスやポート番号を発見します。
また、service にはヘルスチェックを関連付けることができます。この強力な機能を用いて、ノードで障害が起こったときにウェブロードバランサからスムーズに切り離しを行ったり、データベースの slave で障害時に切り替えを行うなどの操作を行えます。ヘルスチェックは DNS インターフェースでも同様に提供されます。ヘルスチェックでサービスに障害がある場合や、ノードに問題が有る場合はシステムレベルのチェックで障害があるとみなし、DNS インターフェースは自動的にサービスクエリから対象ノードを除外します。
詳細については checks の文章を読んでください。check はスクリプトか TTL 型である必要があります。’script’ と ‘interval’ の指定が必須tです。TTL 型の場合は、’ttl’ のみ指定します。check 名は自動的に “service:” によって生成されます。
service の設定を行うには、エージェント起動時に ‘-config-file’ オプションで指定するか、’-config-dir’ によって指定します(ファイルの拡張子が “.json” でないとおConsul は読み込みません)。check に関する定義を更新する場合は、エージェントに対して ‘SIGUP’ シグナルを送信します。別の方法として、service は HTTP API を通して動的に登録する事も出来ます。
■ Check Definitions / check の定義
http://www.consul.io/docs/agent/checks.html
エージェントの主要な役割の1つは、システムとアプリケーション層のヘルスチェックを管理することです。ヘルスチェックがアプリケーション・レベルであると考えられるとき、service と関連づけられます。check は設定ファイルか、稼働中は HTTP インターフェースを通して追加します。
check は2種類あります。
- Script + Interval – これらチェックは外部アプリケーションの呼び出しに依存します。依存するのは、ヘルスチェックと、終了コード(exit code)です。場合によっては出力もあるでしょう。script は実行間隔(例えば 30 秒毎)とセットになります。この仕組みは Nagios プラグインと似ているものです。
- TTL – TTL として指定した時間、最新の check で取得した state を維持します。特定の check に対する状態(state)は、HTTP インターフェースを通して定期的に更新が必要です。外部のシステムが指定した TTL で更新できなかった場合、check は failed の状態となります。この仕組みは、アプリケーションが直接ヘルス状況を報告するために使用します。たとえば、ウェブアプリは、エンドポイントに対して定期的に curl を実行し、もしも失敗した場合 TTL が期限切れになり、ヘルスチェックの状態が critical になります。この仕組みはデッドマン装置 ( dead man’s switch ) と概念的には類似しています。
Check の定義
check を定義するスクリプトは以下の様なものです。
{ "check": { "id": "mem-util", "name": "Memory utilization", "script": "/usr/local/bin/check_mem.py", "interval": "10s" } }
TTL 型のものと非常に似ています。
{ "check": { "id": "web-app", "name": "Web App Status", "notes": "Web app does a curl internally every 10 seconds", "ttl": "30s" } }
いずれの型でも ‘name’ の定義は必須ですが、’id’ と ‘notes’ フィールドはオプションです。’id’ が無い場合は ‘name’ のものが割り当てられます。全ての check はユニークな ID を持つ必要があるので、名前が重複しないように、ユニークな ID が割り当てられるべきです。
‘notes’ フィールドは Consul にとって必要ありませんが、人間が説明を読むために使用することができます。このフィールドは script によって生成させたり、TTL 更新のタイミングで ‘notes’ を更新させたりできます。
check の設定を行うには、エージェント起動時に ‘-config-file’ オプションで指定するか、’-config-dir’ によって指定します(ファイルの拡張子が “.json” でないとおConsul は読み込みません)。check に関する定義を更新する場合は、エージェントに対して ‘SIGUP’ シグナルを送信します。別の方法として、check は HTTP API を通して動的に登録する事も出来ます。
チェック用スクリプト
check 用のスクリプトは、通常、check の status を示すものであれば何でも利用出来ます。唯一の制限があるとすると、終了コード ( exit code ) で状況を明示しなくてはいけません。具体的には、
- Exit code 0 – チェックは正常 ( passing )
- Exit code 1 – チェックは異常 ( warning )
- その他のコード – チェックに失敗
これは Consul が依存する唯一の規則です。なお、人間のオペレータが参照できるように、スクリプトの結果を note フィールドに書き込むような事もできます。
—-
以上、Consul の動作を理解する上での手助けになりましたら幸いです。