Consulを使ってみた

Consulを使ってみた はてなブックマーク - Consulを使ってみた


Consul ( http://www.consul.io/ ) という新しいツールが4月17日(日本時間18日)に発表されました。Vagrant や Serf の作者さんが所属している Hashicorp 社としての新しいプロダクトです。

サイトによると、Consul は、’solution for service discovery and configuration’ とあり、サービス検出と設定のためのソリューションであり、具体的には、サービス(データベースやメール等々)を監視し、問題発生時にはトラフィックを迂回させるなどといった情報を、KVS を通して提供するもの、と書かれています。

また、複数のデータセンタにまたがる非常に大きなインフラ(基盤)上で、既に数ヶ月間利用されてきた実績もあるようですね。

4/19追記:背景やアーキテクチャのドキュメントは、別途本厄翻訳しました
Consul関連文書の参考訳、Serfとの違い等
http://pocketstudio.jp/log3/2014/04/19/translation_consul_related_documents/
Consul関連ドキュメント(参考訳)Part2 (4/23追記分)
http://pocketstudio.jp/log3/2014/04/23/consul_docs_part2/

■Consulとは

  • サーバとクライアントという2つのコンポーネントで構成され、クラスタを形成する
  • サーバはデータを格納し、複製することが出来る
  • 登録されたサーバとノードは、DNS か HTTP インターフェースを通して取得可能

主要な機能は、

  • サービス検出 ( Service Discovery ) … Consul クライアントは、api や mysql 等の ‘service’ を提供し、他のクライアントはこれらサービスを検出するために Consul を用いることが出来る。
  • 障害検知 ( Failure Detection ) … サービス検出とヘルスチェックを用いることで、障害発生時に何かの動作を起こすことができるようになる。
  • キーバリューストレージ ( Key/Value Storage ) … Consul はシンプルな HTTP API を兼ね備えており、様々な目的に利用出来る。
  • 複数データセンタ ( Multi Datacenter ) … 複数のデータをサポートする機能を持つため、複数のデータセンタにまたがるように成長しても、Consul はスケールできる。

とりあえず触ってみた感じとしては、

  • Serf の仕組みも使っているが、別の仕組み(役割)で動くツールであると認識すべき
  • 出来る事が多いので検証項目が多い(ヘルスチェックや、KVS )
  • 実運用に使う場合、Consul + ‘何か’の部分は、自分で実装しなければいけない

このような印象を受けました。

以下、検証と自分向けの簡単なドキュメント整理です。

■とりあえずダウンロードして使ってみる( Getting Started の内容に準じます )

Consul は Serf と同じように、Go 言語で書かれており、バイナリで実行する事が出来ます。ただし、glibc のバージョンが 2.14 以上でないと動作しません。RHEL6/CentOS6 は、そのままだと環境が古いため動かないので要注意です。

$ ./consul
consul: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by consul)

とりあえず、Fedora の新しめの環境が手許にあったので、そちらで試すことにしました。

例によって、consul というバイナリファイルが1個だけ必要です。

wget -O 0.1.0_linux_amd64.zip https://dl.bintray.com/mitchellh/consu/0.1.0_linux_amd64.zip
unzip ./0.1.0_linux_amd64.zip
mv ./consul /usr/bin/
mkdir /opt/consul/

とりあえず起動するときは、consul のサーバとしての起動を行います。以下は自ホストを 192.168.39.5 としている場合です。’-server -bootstrap’ のオプションを用います。

$ consul agent -server -bootstrap -client=192.168.39.5 -dc=local \
    -node=consul1 -data-dir=/tmp/consul  -bind=192.168.39.5

それから別の consul をクラスタに参加させるためには、join を使います。

$ consul agent -dc=local -node=consul2 -data-dir=/tmp/consul2 \
    -bind=192.168.39.6 -join=192.168.39.5

ここでメンバ一覧をチェックしたい場合は【 consul members 】を使います。

$ consul members  -rpc-addr=192.168.39.5:8400
consul1.pocketstudio.net  192.168.39.5:8301  alive  role=consul,dc=local,vsn=1,vsn_min=1,vsn_max=1,port=8300,bootstrap=1
consul2.pocketstudio.net  192.168.39.6:8301  alive  role=node,dc=local,vsn=1,vsn_min=1,vsn_max=1

このように、consul1 と consul2 という2台でクラスタを構成していることがわかります。

■ HTTP API で KVS を試す

consul は KVS の機能を持っており、HTTP を通し JSON 形式のデータをやりとりすることができます。たとば、メンバ一覧を表示するには、次のようにします。

$ curl http://192.168.39.5:8500/v1/catalog/nodes
[{“Node”:”consul1.pocketstudio.net”,”Address”:”192.168.39.5″},{“Node”:”consul2.pocketstudio.net”,”Address”:”192.168.39.6″}]

ポート8500 が標準の HTTP 用のインターフェースです。実行結果は JSON なので、「jq」コマンドを使うと(JSON データを grep したり、awk するようなツールです)、結果が見やすくなります。

$ curl -s http://192.168.39.5:8500/v1/catalog/nodes  | jq '.'
[
  {
    "Address": "192.168.39.5",
    "Node": "consul1.pocketstudio.net"
  },
  {
    "Address": "192.168.39.6",
    "Node": "consul2.pocketstudio.net"
  }
]

では、次にデータを書き込んでみます。  key ‘/hello/key’ に value ‘hello, world!’ をセットしたい場合は、次のようにします。

$ curl -XPUT -d 'hello, world!' http://192.168.39.5:8500/v1/kv/hello/key
true

調子に乗って、もう1つ送ってみます。

$ curl -XPUT -d 'open the next' http://192.168.39.5:8500/v1/kv/hello/key2
true

さて、ここで保管されたデータですが、取り出し時に要注意です。そのまま取得しようとしても、

# curl -s http://192.168.39.5:8500/v1/kv/hello/?recurse | jq '.'
[
  {
    "Value": "b3BlbiB0aGUgbmV4dA==",
    "Flags": 0,
    "Key": "hello/key2",
    "ModifyIndex": 16,
    "CreateIndex": 16
  },
  {
    "Value": "aGVsbG8sIHdvcmxkIQ==",
    "Flags": 0,
    "Key": "hello/key",
    "ModifyIndex": 14,
    "CreateIndex": 14
  }
]

素のまま読む事はできません。データは、base64 でデコードする必要があります。

$ curl -s http://192.168.39.5:8500/v1/kv/hello/key | jq '.[].Value | .' -r | base64 -d
hello, world!

■DNS API を試してみる

DNS インターフェースを兼ね備えているため、ホスト名の名前解決を行う事ができます。そのため、ホスト名さえ把握できれば、仕組み的に IP アドレスを知る必要がなくなります。なお、現時点では、逆引きを行う事はできないようです。

dig を使って名前解決する場合、「-p」でポート番号 8600 を指定します。FQDN の形式は、<consulホスト名>.node.consul になります。データセンタの指定がある場合は、<ホスト名>.node.<データセンタ名>.consul で名前解決をします。

$ dig @192.168.39.5 -p 8600 consul1.node.consul any

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.23.rc1.el6_5.1 <<>> @192.168.39.5 -p 8600 consul1.node.consul any
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8882
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

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

;; ANSWER SECTION:
consul1.node.consul.    0       IN      A       192.168.39.5

このように ANY リクエストで対象ノードの IP アドレスが 192.168.39.5 であるとわかります。

■サービスの登録とヘルスチェック

curl で特定 URL の HTTP 状況を確認し、ヘルスチェックに用いることが出来ます。設定ファイルの置き場所を /etc/consul.d/ とすると、

# mkdir /etc/consul.d/
# echo ‘{“service”: {“name”: “web”, “tags”: [“rails”], “port”: 80, “check”: {“script”: “curl localhost:80 >/dev/null 2>&1”, “interval”: “10s”}}}’ >/etc/consul.d/web.json

このようにファイルを設置します。

consul 起動オプションに -config-dir=/etc/consul.d を付けて再起動すると、チェックが開始されます( Apache 等のログから、10秒おきにアクセスがあることがわかります)。

また、状況は HTTP API を使って確認することもできます。httpd を停止すると、consul のログには次のように表示されます。

2014/04/18 21:58:55 [WARN] Check ‘service:web’ is now critical
2014/04/18 21:58:55 [INFO] agent: Synced check ‘service:web’

この状態でリクエストを投げると、

$ curl http://192.168.39.5:8500/v1/health/state/critical
[{“Node”:”consul1″,”CheckID”:”service:web”,”Name”:”Service ‘web’ check”,”Status”:”critical”,”Notes”:””,”ServiceID”:”web”,”ServiceName”:”web”}]

このように、critical (致命的)なサービスの一覧に ‘web’ として情報が表示されます。

■その他の機能

Serf を使っていて、どこかにデータを保管したいなと思っていましたが、Serf それ自身には機能がありませんでした。そこで Etcd を使って何か実装しなくては、と思っていたのですが、Consul は、まさにそんな目的に合いそうでした。他にも、consul が出来る機能は様々です。色々触って、使いどころを探していきたいなと思っています。

Serf クラスタと Consul クラスタは直接接続できないようなので(バージョンの古いものであれば serf エージェントとして認識できるが、イベント処理はしないので、使いどころが限定される)、イベントやクエリのトリガとなるのは、HTTP API か DNS API と、Serf を組みあわせる部分は、何かしらの実装しがいがある所と思っています。