ども、cloudpack の かっぱ (@inokara) です。
consul が自分の中で熱くなってきているので Docker でコンテナ立てて色々と動かしてみたいと思います。
consul チートシート
前提
- consul と redis 入りの Docker コンテナを利用
- コンテナの起動の際に
--dns
オプション付けて名前解決はローカルホストを利用
docker コンテナを –dns オプション付きで起動
docker run -t --dns=127.0.0.1 -i inokappa/consul-redis /bin/bash
--dns=
でコンテナ内が参照する DNS サーバーを指定することが出来る。なにげに嬉しい。
consul の設定(1)
mkdir /etc/consul.d/ cat << EOT >> /etc/consul.d/consul.json { "ports": { "dns": 53 }, "recursor": "8.8.8.8" } EOT
DNS インターフェースのポートを 53 に固定(デフォルトは 8600
ポート)、consul 内で解決出来ない名前は 8.8.8.8
に問い合わせる設定。(コレ重要)
以下、参考。
consul の起動
consul agent -server -bootstrap -client=127.0.0.1 -dc=local -node=consul1 -data-dir=/tmp/consul -bind=127.0.0.1 -config-dir /etc/consul.d -config-file /etc/consul.d/consul.json &
たくさん起動オプション付けているけど設定ファイル(/etc/consul.d/consul.json
)に加えてもいい。
redis の起動
/usr/local/bin/redis-server & echo "set monitor ok" | redis-cli
ついでに redis 監視用にデータをセットしておく。
redis 監視用スクリプトの設置
redis に事前に登録されているデータを GET
させるチェック。
#!/usr/bin/env bash # echo "set monitor ok" | redis-cli status=`echo -n "GET monitor" | /usr/local/bin/redis-cli` if [ ${status} = "ok" ];then exit 0 else exit 1 fi
redis のポート(6379
)を直接突くチェック。
#!/usr/bin/env bash status=`nc -z localhost 6379` if [ $? = "0" ];then exit 0 else exit 1 fi
どっちか選びましょう。
consul にサービスを登録
cat << EOT | curl -XPUT http://127.0.0.1:8500/v1/agent/service/register -d @- { "name": "redis", "port": 6379, "check": { "script": "/opt/bin/check_redis.sh", "interval": "10s" } } EOT cat << EOT | curl -XPUT http://127.0.0.1:8500/v1/agent/service/register -d @- { "name": "redis-read", "port": 6379, "check": { "script": "/opt/bin/check_redis.sh", "interval": "10s" } } EOT
もしくは、以下のように consul.d
以下に設定ファイルとして置いても良い。
cat << EOT > /etc/consul.d/redis-read.json { "service": { "name": "redis-read", "port": 6379, "check": { "script": "/opt/bin/check_redis.sh", "interval": "10s" } } } EOT cat << EOT > /etc/consul.d/redis.json { "service": { "name": "redis", "port": 6379, "check": { "script": "/opt/bin/check_redis.sh", "interval": "10s" } } } EOT
登録されたサービスの確認
curl -s http://127.0.0.1:8500/v1/catalog/services
jq
なんぞカマスと以下のように。
{ "consul": [], "redis": [], "redis-read": [] }
curl -s http://127.0.0.1:8500/v1/catalog/service/redis
jq
なんぞカマスと以下のように。
[ { "Node": "consul1", "Address": "127.0.0.1", "ServiceID": "redis", "ServiceName": "redis", "ServiceTags": null, "ServicePort": 6379 } ]
curl -s http://127.0.0.1:8500/v1/catalog/service/redis-read
jq
なんぞカマスと以下のように。
[ { "Node": "consul1", "Address": "127.0.0.1", "ServiceID": "redis-read", "ServiceName": "redis-read", "ServiceTags": null, "ServicePort": 6379 } ]
leader ノード確認
Raft leader の確認。
curl -X GET http://localhost:8500/v1/status/leader
DC 内の peer 確認
curl -X GET http://localhost:8500/v1/status/peers
デモっぽいこと
やりたいこと
- アプリケーションから consul に登録されたサービス名を利用する
- Sinatra から Redis にアクセスする際に consul に登録済みのサービス名でアクセスするようにする
Ruby をソースコードからインストール on CentOS 6.x
yum -y install gcc zlib-devel openssl-devel sqlite sqlite-devel cd /usr/local/src wget http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.5.tar.gz tar zxvf ruby-2.1.5.tar.gz cd ruby-2.1.5 ./configure make make install
ついでに Sinatra
Sinatra から Redis を扱いたいのでついでにインストールする。
gem install sinatra --no-ri --no-rdoc -V gem install sinatra-contrib redis hiredis --no-ri --no-rdoc -V
Ruby から redis を扱う
以下、参考。
irb で試す。
# irb irb(main):001:0> require 'redis' => true irb(main):002:0> r=Redis.new host:"redis.service.consul", port: "6379" => #irb(main):003:0> r.set :foo, "bar" => "OK" irb(main):004:0> r.get :foo => "bar" irb(main):005:0> exit
consul に redis という名前でサービスを登録しているのでアプリケーションからも redis.service.consul
という名前で参照出来る。
Ruby から redis を扱う(2)
Write と Read のエンドポイントを変える。
とりあえず、これも irb で試す。
# irb irb(main):001:0> require 'redis' => true irb(main):002:0> r=Redis.new host:"redis.service.consul", port: "6379" => #irb(main):003:0> r.set :foo, "bar" => "OK" irb(main):004:0> rr=Redis.new host:"redis-read.service.consul", port: "6379" => # irb(main):005:0> rr.get :foo => "bar" irb(main):006:0>
consul で Write 用のサービスと Read 用のサービスを別々に登録しているが、先ほどと同様にアプリケーションから参照することが可能。
Sinatra + Redis でちょっとしたアプリ
ちょっとしたアプリのバックエンドに redis のクラスタを置いて、その redis を consul で監視しつつ、ノードの一台に障害が起きてもサービスは一応継続出来るようなシチュエーションを作ってみたい。
#!/usr/bin/env ruby # require 'sinatra' require "sinatra/reloader" require 'redis' require 'json' r = Redis.new host:"redis.service.consul", port:"6379" rr = Redis.new host:"redis-read.service.consul", port:"6379" get '/value/:key' do value = rr.get params[:key] v = { key: params[:key], value: value } v.to_json end post '/data/:key' do msg = request.body.read r.set params[:key], msg end
Sinatra 先生を使って consul に登録された redis サービスに対して読み書き。書き込みは 1 インスタンスの redis-server を consul に登録、読み込みは二つのホストにまたがった 2 つの redis-server インスタンスを consul に登録した。尚、redis-server はレプリケーションを設定。←重要。
consul service id | consul node | DNS Name | 用途 |
---|---|---|---|
redis | consul1(172.17.0.5) | redis.service.consul | 書き込み、読み取り |
redis-read | consul1(172.17.0.5) / consul2(172.17.0.6) | redis-read.service.consul | 読み取り |
アプリケーションの起動は以下のように。
ruby app.rb &
以下のようにデータをポスト。
curl -X POST localhost:4567/data/consul -d 'good'
以下のようにデータを取得。
curl -s -X GET localhost:4567/value/consul | jq .
一応、無駄に JSON で返す実装。
{ "key": "consul", "value": "good" }
例えば、一台の redis-server が死亡しても…
# dig redis-read.service.consul 2014/12/24 15:55:57 [WARN] dns: node 'consul1' failing health check 'service:redis-read: Service 'redis-read' check', dropping from service 'redis-read' ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.30.rc1.el6 <<>> redis-read.service.consul ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33995 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;redis-read.service.consul. IN A ;; ANSWER SECTION: redis-read.service.consul. 0 IN A 172.17.0.6 ;; Query time: 2 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Wed Dec 24 15:55:57 2014 ;; MSG SIZE rcvd: 84
ちゃんと、データへのアクセス(読み取り)は可能。
# curl -s -X GET localhost:4567/value/consul | jq . ::1 - - [24/Dec/2014:15:57:29 +0000] "GET /value/consul HTTP/1.1" 200 31 0.0007 localhost - - [24/Dec/2014:15:57:29 GMT] "GET /value/consul HTTP/1.1" 200 31 - -> /value/consul { "key": "consul", "value": "good" }
もちろん、書き込みは残念ながらエラーになるが、redis のレプリケーションと consul のサービス監視と DNS 機能によって完全ではないもののサービスを継続することは出来そう。(読み取りだけでサービスを提供している間に死亡した redis-server を復旧する等の時間稼ぎくらいには使えそう)
ということで…
まだまだ理解出来ていない機能があったりするが consul ってどんなふうに使うのか?というのはちょっとしたアプリケーションを動かしてみてザクッと理解出来たので引き続き紐解いていきたいですなあ。
元記事はこちらです。
「俺の consul チートシート」