Chef ProvisioningとVagrantでConsulクラスタ環境を作成する #getchef #vagrant #consul
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
はじめに
本稿では、Chef Provisioning と Vagrant (VirtualBox) を用いて、テスト用の Consul クラスタを作成してみます。非常に簡単な例なので、そのまま実環境に流用できるものではありません。ただ、Chef Provisioning の利用例や consul クラスタの挙動をつかむには十分だと思います。本稿で使用したソースコードはすべて https://github.com/cl-lab-k/chef-consul-cluster にあります。
Consul、Vagrant とは
Consul とは、米 HashiCorp 社が開発する、サービスの検出と設定を行うための仕組みです。クライアント・サーバ型の構成で動作し、キーバリューストア(KVS) に保持したデータを DNS や HTTP インターフェイスで取得できます。クライアントとサーバはそれぞれがクラスタを構成し、インターネット越しに別々のデータセンターをまたいで接続することもできます。
Vagrant とは、こちらも米 HashiCorp 社が開発する、仮想環境を自動で構築するツールです。簡単な設定ファイルで非常に手軽に仮想仮想を作成することができます。
Chef Provisioningとは
Chef Provisioning (旧称:Chef Metal) とは、米 Chef 社が開発するクラスタ管理フレームワークです。Chef の Recipe でマシンを管理することと同じように、クラスタを管理することができます。
事前準備
実験は Debian GNU/Linux 8.1 上で行いました。以下のパッケージやプラグインをインストールし
ています。
- Chef-DK 0.6.0
- Vagrant 1.7.2
- Vagrant プラグイン: vagrant-hostsupdater 0.0.11
- Vagrant プラグイン: vagrant-cachier 1.2.0
- VirtualBox 4.3.28
ソースコードの取得
https://github.com/cl-lab-k/chef-consul-cluster/tree/sample_blog を clone します。
% git clone https://github.com/cl-lab-k/chef-consul-cluster -b sample_blog
Cloning into 'chef-consul-cluster'...
:
% cd chef-consul-cluster
%
以降はこのツリー内で作業を行います。
Chef-Server VM の作成
Chef Provisioning を用いて、Chef-Server 12 用の仮想マシンを作成します。provisioning/chef-server ディレクトリに移動します。
% cd provisioning/chef-server
% ls -la
合計 24
drwxr-xr-x 2 d-higuchi d-higuchi 4096 6月 12 11:57 .
drwxr-xr-x 4 d-higuchi d-higuchi 4096 6月 12 11:21 ..
-rw-r--r-- 1 d-higuchi d-higuchi 73 6月 11 18:23 Berksfile
-rw-r--r-- 1 d-higuchi d-higuchi 405 6月 12 11:24 Rakefile
-rw-r--r-- 1 d-higuchi d-higuchi 971 6月 12 11:57 chef-server.rb
-rw-r--r-- 1 d-higuchi d-higuchi 181 6月 12 11:25 destroy.rb
%
設定は chef.json ファイルで行えますが、通常は変更する必要はないでしょう。一連の作業は基本的に rake タスクとして定義してあります。デフォルトでは berks vendor サブコマンドを実行して chef-server Cookbook を取得し、Chef Provisioning によって Chef-Server 12 用の VirtualBox VM を Vagrant で作成します。Rakefile を見ての通り、Chef Provisioning は Chef ローカルモードを利用しています(chef-client -z)。
% rake
berks vendor cookbooks
Resolving cookbook dependencies...
Fetching cookbook index from https://supermarket.chef.io...
Using chef-server (3.1.1)
Using packagecloud (0.0.19)
Using chef-server-ingredient (0.4.0)
:
:
:
Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 244.394462204 seconds
%
これで https://chef-server.example.jp (192.168.33.10) に Chef-Server 12 用の VM が起動しました。本実験では必要ないため、Chef Manage アドオンをインストールしていないので Web UI はありません。
Chef-Server にポリシーをアップロード
Chef-Server に User と Organization を作成し、両者の鍵を取得、knife.rb を作成、knife ssl fetch を実行して鍵取得(参考: Chef 12の新機能: knife ssl check/fetch)、berks vendor コマンドと berks upload コマンドを実行して必要な Cookbook の習得とアップロード、Role のアップロードを行います。各ポリシーの詳細については、実際のクラスタの動作の説明の際に併せて行います。
設定は Chef-Server 用 VM の場合と同じく chef.json ファイルで行えますが、通常は変更する必要はないでしょう。roles/chef-consul-cluster-base.json は、HashiCorp 社が提供するさまざまなツールを統合したインフラ管理サービスである Atlas のアカウント情報を記載してください。これを用いて自動的に Consul クラスタを構築します。詳しくは Consulサーバクラスタ構成手順の歴史 を参照してください。
こちらも作業は rake タスクとして定義してあります。ディレクトリトップに戻り、rake config と実行してください。
% rake config
ssh -i ~/.chef/vms/.vagrant/machines/chef-server/virtualbox/private_key vagrant@chef-server.example.jp 'sudo chef-server-ctl user-create testuser TEST USER testuser@example.jp
testpswd --filename testuser.pem'
scp -i ~/.chef/vms/.vagrant/machines/chef-server/virtualbox/private_key vagrant@chef-server.example.jp:testuser.pem /tmp/chef-serf-cluster/provisioning/vms/../../.chef/testuser.pem
:
:
:
knife role from file roles/chef-consul-cluster-*.json
Updated Role chef-consul-cluster-client!
Updated Role chef-consul-cluster-lb!
Updated Role chef-consul-cluster-server!
%
クラスタ用 VM の作成
ここでは次の VM を作成します。
- Consul サーバクラスタ用 VM ... 3台
- Consul クライアント + Nginx ウェブサーバ用 VM ... 2台
- Nginx ロードバランサ用 VM ... 1台
計 6台となります。
Consul は Serf と異なり、クライアント・サーバ構成を取ります。また、Consul サーバはクラスタとして動作します。1台でも動作しますが、冗長性・耐障害性を高めるために 3台あるいは 5台での運用が推奨されています(参考: Deployment Table)。ここでは 3台の Consul サーバによるクラスタを構築することとします。
さらに Serf と異なる点として、Consul はサービスの監視を行うことができます。Serf では Serf エージェントが起動しているか停止しているかどうかが主要なトリガーでした。Consul では、Consul クライアントが定義内容に従って行うサービスの死活監視がトリガーとなります。これにより、Consul クライアントは生きているがサービスの応答がない、というような状態を知ることができます。ここでは Consul クライアントが自マシン上の Nginx ウェブサーバの死活監視を行うこととします。
Nginx ロードバランサは Consul サーバクラスタに問い合わせを行い、その結果を利用して 2台ある Nginx ウェブサーバへの振り分けを行います。Consul はキーバリューストア機能でデータを保持し、Web UI、HTTP、DNS でデータを取り出すことができます。ここでは DNS を用いて Consul サーバクラスタへの問い合わせを行うこととします。
provisioning/vms ディレクトリに移動します。
% cd provisioning/vms
合計 16
drwxr-xr-x 2 d-higuchi d-higuchi 4096 6月 24 16:23 .
drwxr-xr-x 4 d-higuchi d-higuchi 4096 6月 12 11:21 ..
-rw-r--r-- 1 d-higuchi d-higuchi 620 6月 19 12:55 Rakefile
-rw-r--r-- 1 d-higuchi d-higuchi 1828 6月 24 16:23 vms.rb
%
設定はやはり chef.json ファイルで行えますが、通常は変更する必要はないでしょう。
こちらも作業は rake タスクとして定義してあります。デフォルトでは Chef Provisioning によってクラスタ用の VirtualBox VM を Vagrant で 6台作成します。作成した Serf ノード用 VM の Node Object は Chef-Server 12 に登録され、先にアップロードしてあったポリシーを適用して収束を行います。Rakefile では Chef Provisioning は Chef ローカルモードを利用しています(chef-client -z)が、これはあくまで Chef Provisioning が必要としているものなので、混同しないようにしてください。また同じような多数の VM を起動するため、vagrant-cachier プラグインを用いてパッケージをキャッシュし、少しでもかかる時間を短くしようとしてあります。
% rake
CHEF_DRIVER=vagrant chef-client -z vms.rb
:
:
:
Running handlers:
Running handlers complete
Chef Client finished, 6/6 resources updated in 1040.9932162979999 seconds
- 192.168.33.101 (srv101, Consul サーバ 1)
- 192.168.33.102 (srv102, Consul サーバ 2)
- 192.168.33.103 (srv103, Consul サーバ 3)
- 192.168.33.201 (node201, Consul クライアント 1)
- 192.168.33.202 (node202, Consul クライアント 2)
- 192.168.33.211 (lb211, ロードバランサ)
の 6台のクラスタ用 VM が起動しました。
本実験では vagrant-hostsupdater を用いて、ホスト側の /etc/hosts を更新するようになっています。
% tail -8 /etc/hosts
192.168.33.10 chef-server # VAGRANT: 001f4c711f6f0fe6cb9c2fbe9deff7f9 (chef-server) / 335c6551-df64-4875-abaf-93bdab933ddb
192.168.33.10 chef-server.example.jp # VAGRANT: 001f4c711f6f0fe6cb9c2fbe9deff7f9 (chef-server) / 335c6551-df64-4875-abaf-93bdab933ddb
192.168.33.101 srv101 # VAGRANT: f84444817f9ea53b0146d36b798032b2 (srv101) / eb4242da-9ec0-4649-a029-a4b610e7aebd
192.168.33.102 srv102 # VAGRANT: 87ae7195da722db43fcfafd9e4116a40 (srv102) / 50a467b9-2f30-4a95-931c-41ac3cb39490
192.168.33.103 srv103 # VAGRANT: 9bb557abb97848f38ea26d613b17839f (srv103) / e8381324-69b8-43a0-9cba-e08c4721d5f6
192.168.33.201 node201 # VAGRANT: 51bfdec166295f56b51d8aac2d0f2178 (node201) / 2f9689b8-3791-4ba6-ae65-30b75ab4e814
192.168.33.202 node202 # VAGRANT: bebe23337a2616c382d13cfe7c0a4ae6 (node202) / 4bf047d4-6359-4505-8acb-a4e60377ee55
192.168.33.211 lb211 # VAGRANT: 88fc4c9b4e629ed1288eb21c473ed89c (lb211) / 00185a52-8f7c-4f5a-83c4-3a60473c869a
%
クラスタの動作
このクラスタ構成図で示される、各マシンの役割と動作を見ていきます。
Consul サーバ
Consul サーバは consul Cookbook を適用しています。Atlas による自動クラスタ構築を利用し、3台の Consul サーバクラスタを構築しています。詳しくは Consulサーバクラスタ構成手順の歴史 を参照してください。
また、Web UI、HTTP、DNS の各インターフェイスをパブリックに提供しています。アクセス制限や暗号化を行っていないので、パブリックネットワークに向けてこのまま流用しないでください。
Consul クライアント + Nginx ウェブサーバ
Consul クライアントはサーバと同様 consul Cookbook を適用しています。こちらも Atlas による自動クラスタ構築を利用し、自動的にサーバクラスタに参加するようになっています。
chef-consul-cluster::web Recipe では nginx Cookbook を適用しての Nginx ウェブサーバの設定と、Consul クライアントが監視を行うサービスの定義を行っています。Consul クライアントは script で指定したコマンドを interval で指定した間隔で実行し、返り値によって死活監視を行います。
Nginx ロードバランサ
Nginx ロードバランサは、Consul サーバも Consul クライアントも実行していません。dnsmasq Cookbook を適用して設定した dnsmasq を通して Consul サーバクラスタに DNS 問い合わせを行い、その結果でウェブサーバの振り分けを行います。これは一体どういうことでしょうか。理屈を見てみましょう。
まず chef-consul-cluster-lb Role にて、dnsmasq の設定を行っています。これは consul というドメインへの問い合わせは Consul サーバクラスタに対して DNS 問い合わせを行うという設定です。次に lb Recipe では、web.service.consul をアップストリームとなるように設定を行っています。
Consul から DNS でクラスタの状況を取得する場合、consul というドメインを通して問い合わせを行います。例えば、srv101 というホストの IP アドレスを取得するには、次のようにします。8600 は Consul が提供する DNS サーバのポート番号です。
% dig @192.168.33.101 -p 8600 srv101.node.consul
; <<>> DiG 9.9.5-9-Debian <<>> @192.168.33.101 -p 8600 srv101.node.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34476
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;srv101.node.consul. IN A
;; ANSWER SECTION:
srv101.node.consul. 0 IN A 192.168.33.101
;; Query time: 2 msec
;; SERVER: 192.168.33.101#8600(192.168.33.101)
;; WHEN: Thu Jun 25 18:32:46 JST 2015
;; MSG SIZE rcvd: 70
先に Consul クライアントでは、chef-consul-cluster::web Recipe でサービスの定義を行いました。サービスの名前は name で指定し、ここでは web としています。web サービスを定義している Consul クライアントの IP アドレスをすべて取得してみましょう。
% dig @192.168.33.101 -p 8600 web.service.consul
; <<>> DiG 9.9.5-9-Debian <<>> @192.168.33.101 -p 8600 web.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12164
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, 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.202
web.service.consul. 0 IN A 192.168.33.201
;; Query time: 2 msec
;; SERVER: 192.168.33.101#8600(192.168.33.101)
;; WHEN: Thu Jun 25 18:35:11 JST 2015
;; MSG SIZE rcvd: 104
このように、node201 と node202 の IP アドレスが取得できました。もうおわかりでしょう。web.service.consul に対してアクセスしようとすると、Consul サーバクラスタに DNS 問い合わせが行われ、node201 と node202 の IP アドレスが得られ、そのどちらかに実際のアクセスが行われることになります。もしサービスが停止した場合、DNS の問い合わせからそのノードは取り除かれます。
実際の動作
では、ロードバランサにアクセスしてみましょう。curl コマンドを使います。
% curl http://lb211/
node202
% curl http://lb211/
node201
% curl http://lb211/
node202
% curl http://lb211/
node201
% curl http://lb211/
node202
% curl http://lb211/
node201
% curl http://lb211/
node202
% curl http://lb211/
node201
% curl http://lb211/
node202
% curl http://lb211/
node201
%
このように、ロードバランサにアクセスするたびに、返ってくる値が異なっています。
dig コマンドで DNS も確認してみましょう。
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
192.168.33.202
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.202
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
192.168.33.202
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.202
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
192.168.33.202
%
このように node201 と node202 が交互になっています。想定通りに動作していると言っていいでしょう。
ここで、node202 側の Nginx を停止してしまいましょう。
vagrant@node202:~$ sudo service nginx stop
vagrant@node202:~$
再び curl コマンドでロードバランサにアクセスしてみます。
% curl http://lb211/
node201
% curl http://lb211/
node201
% curl http://lb211/
node201
% curl http://lb211/
node201
% curl http://lb211/
node201
%
このように node201 しか返ってこなくなりました。dig コマンドで DNS も確認します。
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
%
やはり node201 しか返らなくなっています。想定した通りの動作です。
node202 の Nginx を起動し、curl コマンドと dig コマンドで確認してみます。
vagrant@node202:~$ sudo service nginx start
vagrant@node202:~$
% curl http://lb211/
node201
% curl http://lb211/
node202
% curl http://lb211/
node201
% curl http://lb211/
node202
% curl http://lb211/
node201
% curl http://lb211/
node202
%
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
192.168.33.202
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.202
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
192.168.33.202
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.202
192.168.33.201
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.201
192.168.33.202
% dig @srv101 -p 8600 web.service.consul +short
192.168.33.202
192.168.33.201
再び node202 も返ってくるようになりました。
ここでは node202 の Nginx を停止しただけですが、node202 の Consul エージェントを停止したり、node202 のマシンそのものを停止しても同様の結果となります。
まとめ
本稿では、Chef Provisioning と Vagrant (VirtualBox) を用いて、テスト用の Consul クラスタを作成してみました。Chef Provisioning を使った Chef-Server/Client 環境の作成、Consul サーバクラスタとクライアントの動作と活用例について、概要をつかんでいただけたと思います。
本実験では Chef は Consul クラスタ環境の作成のみに使い、その後のクラスタ環境の変更には用いていません。Consul エージェントと Chef Client の組み合わせは今後の課題です。