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

参考サイト