Consul
2016/4/4更新
対応バージョン: 0.6.4
4台のCentOS 7上にConsulのサーバとクライアント3台を設定してクラスタ構成とし、クライアント側でApacheを動作させてみる。
各ノードはVirtualBox上の仮想マシンとするが仮想マシンの作成手順については割愛する。
尚、各ノードのIPアドレスは以下の通りする。
サーバ
s1: 192.168.33.11
クライアント
c1: 192.168.33.21
c2: 192.168.33.22
c3: 192.168.33.23
以降の作業は各ノード上にて実施する。
準備するもの
全ノードに対して以下を実行する。
関連パッケージ
unzipとdigを使用するのであらかじめインストールしておく。
% sudo yum -y install unzip bind-utils
Consul本体
以下のダウンロードページよりConsulのバイナリモジュール(consul_0.6.4_linux_amd64.zip)を入手する。
ここではLinux(64bit)を使用するものとする。
ダウンロードしたzipファイルを展開するとconsulというバイナリが現れるので/usr/local/sbinに配置する。インストールはこれで完了である。
% unzip consul_0.6.4_linux_amd64.zip % sudo install consul /usr/local/sbin % rm consul_0.6.4_linux_amd64.zip consul % consul -v Consul v0.6.4 Consul Protocol: 3 (Understands back to: 1)
インストールしたconsulバイナリはConsulエージェントと呼び、単一のバイナリで起動オプションによってサーバ/クライアント双方の役割を担うことができる。
サーバ/クライアントどちらのモードで起動しても以下のサービスが提供される。
8400番ポート: RPC
8500番ポート: HTTP
8600番ポート: DNS
サーバ起動
s1上でConsulエージェントをサーバモードで起動する。起動オプションは以下の通りである。
-server
サーバモード
-bootstrap-expect
Consulエージェントの数(まずは1)
-data-dir
クラスタ用データを保管するディレクトリ(任意)
-bind
Consulエージェントをバインドするネットワークインタフェース(自ノードのIPアドレス)
s1% consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -bind 192.168.33.11 ==> WARNING: BootstrapExpect Mode is specified as 1; this is the same as Bootstrap mode. ==> WARNING: Bootstrap mode enabled! Do not enable unless necessary ==> Starting Consul agent... ==> Starting Consul agent RPC... ==> Consul agent running! Node name: 's1' Datacenter: 'dc1' Server: true (bootstrap: true) Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400) Cluster Addr: 192.168.33.11 (LAN: 8301, WAN: 8302) Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false Atlas: <disabled> ==> Log data will now stream in as it occurs: 2016/04/03 22:55:30 [INFO] serf: EventMemberJoin: s1 192.168.33.11 2016/04/03 22:55:30 [INFO] serf: EventMemberJoin: s1.dc1 192.168.33.11 2016/04/03 22:55:30 [INFO] raft: Node at 192.168.33.11:8300 [Follower] entering Follower state 2016/04/03 22:55:30 [INFO] consul: adding LAN server s1 (Addr: 192.168.33.11:8300) (DC: dc1) 2016/04/03 22:55:30 [INFO] consul: adding WAN server s1.dc1 (Addr: 192.168.33.11:8300) (DC: dc1) 2016/04/03 22:55:30 [ERR] agent: failed to sync remote state: No cluster leader 2016/04/03 22:55:31 [WARN] raft: Heartbeat timeout reached, starting election 2016/04/03 22:55:31 [INFO] raft: Node at 192.168.33.11:8300 [Candidate] entering Candidate state 2016/04/03 22:55:31 [INFO] raft: Election won. Tally: 1 2016/04/03 22:55:31 [INFO] raft: Node at 192.168.33.11:8300 [Leader] entering Leader state 2016/04/03 22:55:31 [INFO] consul: cluster leadership acquired 2016/04/03 22:55:31 [INFO] consul: New leader elected: s1 2016/04/03 22:55:31 [INFO] raft: Disabling EnableSingleNode (bootstrap) 2016/04/03 22:55:31 [INFO] consul: member 's1' joined, marking health alive 2016/04/03 22:55:32 [INFO] agent: Synced service 'consul'
ここでクラスタメンバを確認するとサーバが表示される。
s1% consul members Node Address Status Type Build Protocol DC s1 192.168.33.11:8301 alive server 0.6.4 2 dc1
ノード情報はHTTPサーバで確認できる。
s1% curl http://127.0.0.1:8500/v1/catalog/nodes [{"Node":"s1","Address":"192.168.33.11","TaggedAddresses":{"wan":"192.168.33.11"},"CreateIndex":3,"ModifyIndex":4}]
DNS情報も以下のようにして確認できる。
s1% dig @127.0.0.1 -p 8600 s1.node.consul ; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> @127.0.0.1 -p 8600 s1.node.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56704 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;s1.node.consul. IN A ;; ANSWER SECTION: s1.node.consul. 0 IN A 192.168.33.11 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: 日 4月 03 23:00:12 JST 2016 ;; MSG SIZE rcvd: 62
クライアント起動
c1〜c3上でそれぞれConsulエージェントをクライアントモードで起動する。起動オプションは以下の通りである。
-data-dir
クラスタ用データを保管するディレクトリ(任意)
-bind
Consulエージェントをバインドするネットワークインタフェース(自ノードのIPアドレス)
-join
サーバのIPアドレス
c1
c1% consul agent -data-dir /tmp/consul -bind 192.168.33.21 -join 192.168.33.11 ==> Starting Consul agent... ==> Starting Consul agent RPC... ==> Joining cluster... Join completed. Synced with 1 initial agents ==> Consul agent running! Node name: 'c1' Datacenter: 'dc1' Server: false (bootstrap: false) Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400) Cluster Addr: 192.168.33.21 (LAN: 8301, WAN: 8302) Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false Atlas: <disabled> ==> Log data will now stream in as it occurs: 2016/04/03 23:04:32 [INFO] serf: EventMemberJoin: c1 192.168.33.21 2016/04/03 23:04:32 [INFO] agent: (LAN) joining: [192.168.33.11] 2016/04/03 23:04:32 [INFO] serf: EventMemberJoin: s1 192.168.33.11 2016/04/03 23:04:32 [INFO] agent: (LAN) joined: 1 Err: <nil> 2016/04/03 23:04:32 [INFO] consul: adding server s1 (Addr: 192.168.33.11:8300) (DC: dc1) 2016/04/03 23:04:32 [INFO] agent: Synced node info
c2
c2% consul agent -data-dir /tmp/consul -bind 192.168.33.22 -join 192.168.33.11 ==> Starting Consul agent... ==> Starting Consul agent RPC... ==> Joining cluster... Join completed. Synced with 1 initial agents ==> Consul agent running! Node name: 'c2' Datacenter: 'dc1' Server: false (bootstrap: false) Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400) Cluster Addr: 192.168.33.22 (LAN: 8301, WAN: 8302) Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false Atlas: <disabled> ==> Log data will now stream in as it occurs: 2016/04/03 23:10:31 [INFO] serf: EventMemberJoin: c2 192.168.33.22 2016/04/03 23:10:31 [INFO] agent: (LAN) joining: [192.168.33.11] 2016/04/03 23:10:31 [INFO] serf: EventMemberJoin: s1 192.168.33.11 2016/04/03 23:10:31 [INFO] serf: EventMemberJoin: c1 192.168.33.21 2016/04/03 23:10:31 [INFO] agent: (LAN) joined: 1 Err: <nil> 2016/04/03 23:10:31 [INFO] consul: adding server s1 (Addr: 192.168.33.11:8300) (DC: dc1) 2016/04/03 23:10:31 [INFO] agent: Synced node info
c3
c3% consul agent -data-dir /tmp/consul -bind 192.168.33.23 -join 192.168.33.11 ==> Starting Consul agent... ==> Starting Consul agent RPC... ==> Joining cluster... Join completed. Synced with 1 initial agents ==> Consul agent running! Node name: 'c3' Datacenter: 'dc1' Server: false (bootstrap: false) Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400) Cluster Addr: 192.168.33.23 (LAN: 8301, WAN: 8302) Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false Atlas: <disabled> ==> Log data will now stream in as it occurs: 2016/04/03 23:10:35 [INFO] serf: EventMemberJoin: c3 192.168.33.23 2016/04/03 23:10:35 [INFO] agent: (LAN) joining: [192.168.33.11] 2016/04/03 23:10:35 [INFO] serf: EventMemberJoin: c2 192.168.33.22 2016/04/03 23:10:35 [INFO] serf: EventMemberJoin: s1 192.168.33.11 2016/04/03 23:10:35 [INFO] serf: EventMemberJoin: c1 192.168.33.21 2016/04/03 23:10:35 [INFO] agent: (LAN) joined: 1 Err: <nil> 2016/04/03 23:10:35 [INFO] consul: adding server s1 (Addr: 192.168.33.11:8300) (DC: dc1) 2016/04/03 23:10:35 [INFO] agent: Synced node info
改めてクラスタメンバを確認するとサーバとクライアント3台が表示される。
s1% consul members Node Address Status Type Build Protocol DC c1 192.168.33.21:8301 alive client 0.6.4 2 dc1 c2 192.168.33.22:8301 alive client 0.6.4 2 dc1 c3 192.168.33.23:8301 alive client 0.6.4 2 dc1 s1 192.168.33.11:8301 alive server 0.6.4 2 dc1
動作確認
オーケストレーション機能
クラスタメンバに対して一括でコマンドを実行することができる。
例)
s1% consul exec hostname s1: s1 s1: ==> s1: finished with exit code 0 c3: c3 c3: c1: c1 c1: c2: c2 c2: ==> c3: finished with exit code 0 ==> c1: finished with exit code 0 ==> c2: finished with exit code 0 4 / 4 node(s) completed / acknowledged
サービスディスカバリ機能
クライアント3台に対してApacheを導入し、DNSにサービスが登録されていることを確認する。
作業は別ターミナルで各ノードにログインして実行する。どのノードにアクセスしているか分かりやすくするために各ノードのホスト名をindex.htmlに書き込む。
% sudo yum -y install httpd % sudo sh -c "hostname > /var/www/html/index.html" % sudo systemctl restart httpd % curl http://127.0.0.1
ここでいったんConsulエージェントをCtrl + Cで停止し、Consul用のサービス定義を追加する。
% sudo mkdir /etc/consul.d % sudo vi /etc/consul.d/web.json { "service": { "name": "web", "port": 80 "check": { "script": "curl localhost:80 > /dev/null 2>&1", "interval": "15s" } } }
それぞれのパラメータの意味は以下の通りである。
"name"
サービス名(任意)
"port"
サービスポート(任意)
"check"
ヘルスチェック定義("script"でチェック方法、"interval"でチェック間隔を指定)
定義が作成できたら再びConsulエージェントを起動する。今度は-config-dirオプションに/etc/consul.dを指定する。
(c1)
c1% consul agent -data-dir /tmp/consul -config-dir /etc/consul.d -bind 192.168.33.21 -join 192.168.33.11
(c2)
c2% consul agent -data-dir /tmp/consul -config-dir /etc/consul.d -bind 192.168.33.22 -join 192.168.33.11
(c3)
c3% consul agent -data-dir /tmp/consul -config-dir /etc/consul.d -bind 192.168.33.23 -join 192.168.33.11
コンソール上には以下のログが出力される。
2016/04/04 00:20:20 [INFO] agent: Synced service 'web' 2016/04/04 00:20:27 [INFO] agent: Synced check 'service:web'
ここでサービス名の名前解決を行ってみるとサービスが稼動している3台のノードが返される。
s1% dig @127.0.0.1 -p 8600 web.service.consul ; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> @127.0.0.1 -p 8600 web.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11654 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;web.service.consul. IN A ;; ANSWER SECTION: web.service.consul. 0 IN A 192.168.33.21 web.service.consul. 0 IN A 192.168.33.22 web.service.consul. 0 IN A 192.168.33.23 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: 月 4月 04 00:26:29 JST 2016 ;; MSG SIZE rcvd: 138
逆引きも正常に機能する。
s1% dig @127.0.0.1 -p 8600 web.service.consul SRV ; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> @127.0.0.1 -p 8600 web.service.consul SRV ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32159 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 3 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;web.service.consul. IN SRV ;; ANSWER SECTION: web.service.consul. 0 IN SRV 1 1 80 c1.node.dc1.consul. web.service.consul. 0 IN SRV 1 1 80 c2.node.dc1.consul. web.service.consul. 0 IN SRV 1 1 80 c3.node.dc1.consul. ;; ADDITIONAL SECTION: c1.node.dc1.consul. 0 IN A 192.168.33.21 c2.node.dc1.consul. 0 IN A 192.168.33.22 c3.node.dc1.consul. 0 IN A 192.168.33.23 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: 月 4月 04 00:27:39 JST 2016 ;; MSG SIZE rcvd: 306
dnsmasqを使った名前解決とラウンドロビン
dnsmasqを使うと上記でdigを使わなくてもローカルでConsulのサービスと連携した名前解決が簡単にできる。
まずdnsmasqの設定に以下の内容を追記する。
s1% sudo sh -c "echo 'server=/consul/127.0.0.1#8600' >> /etc/dnsmasq.conf" s1% sudo sh -c "echo 'strict-order' >> /etc/dnsmasq.conf"
DNSサーバの指定は/etc/resolv.confによって行うが、同ファイルはNetworkManagerによって管理されていてデフォルトではDHCPサーバから取得したDNSサーバが書き込まれる設定になっているのでいったんこの連動機能をオフにして代わりにローカルホストを指定する。
s1% cat /etc/resolv.conf # Generated by NetworkManager nameserver 10.0.2.3 s1% nmcli con 名前 UUID タイプ デバイス enp0s3 037b88a5-0dc5-4a49-9886-d5df37c785de 802-3-ethernet enp0s3 s1% sudo nmcli con mod enp0s3 ipv4.ignore-auto-dns yes s1% sudo nmcli con mod enp0s3 ipv4.dns 127.0.0.1 s1% sudo systemctl restart NetworkManager s1% cat /etc/resolv.conf # Generated by NetworkManager nameserver 127.0.0.1
/etc/resolv.confの設定が終わったらdnsmasqサービスを有効化する。
s1% sudo systemctl enable dnsmasq s1% sudo systemctl start dnsmasq
これでdig使用時にポート番号を指定する必要がなくなるので単に以下のようにすればサービスの名前解決ができるようになる。
s1% dig web.service.consul ; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> web.service.consul ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12355 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;web.service.consul. IN A ;; ANSWER SECTION: web.service.consul. 0 IN A 192.168.33.21 web.service.consul. 0 IN A 192.168.33.22 web.service.consul. 0 IN A 192.168.33.23 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: 月 4月 04 01:02:25 JST 2016 ;; MSG SIZE rcvd: 138
あとは実際にweb.service.consulにHTTPアクセスしてみてリクエストが各ノードに振り分けられていることを確認する。
s1% curl http://web.service.consul c1 s1% curl http://web.service.consul c2 s1% curl http://web.service.consul c2 s1% curl http://web.service.consul c1 s1% curl http://web.service.consul c3 s1% curl http://web.service.consul c1 s1% curl http://web.service.consul c2
参考サイト
Consul技術情報 (Qiita)
Serf/Consulで管理を自動化! ~実践的な手法を紹介~ (技術評論社)
Consulと自作OSSを活用した100台規模のWebサービス運用 (YAPC::Asia Tokyo 2015)