fbpx

CL LAB

HOME > CL LAB > Chef > Chef ProvisioningとVagrantでSerfクラスタ環境を作成する #getchef #vagrant #serf

Chef ProvisioningとVagrantでSerfクラスタ環境を作成する #getchef #vagrant #serf

 ★ 119

はじめに

本稿では、Chef Provisioning と Vagrant (VirtualBox) を用いて、テスト用の Serf クラスタを作成してみます。非常に簡単な例なので、そのまま実環境に流用できるものではありません。ただ、Chef Provisioning の利用例や Serf クラスタの挙動をつかむには十分だと思います。本稿で使用したソースコードはすべて https://github.com/cl-lab-k/chef-serf-cluster にあります。

Serf、Vagrantとは

Serf とは、米 HashiCorp 社が開発するクラスタ管理ツールです。軽量なエージェントと簡単な設定ファイルのみで動作し、非常に手軽にクラスタを構築することができます。

Vagrant とは、こちらも米 HashiCorp 社が開発する、仮想環境を自動で構築するツールです。簡単な設定ファイルで非常に手軽に仮想仮想を作成することができます。

Chef Provisioningとは

Chef Provisioning (旧称:Chef Metal)とは、米 Chef 社が開発するクラスタ管理フレームワークです。Chef の Recipe でマシンを管理することと同じように、クラスタを管理することができます。

事前準備

実験は Debian GNU/Linux 8.1 上で行いました。以下のパッケージやプラグインをインストールしています。

Chef-DK 0.6.0 に同梱の Chef Client 12.3.0 には、/opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rbfixes access keys attribute in knife show の修正を適用しています。本実験では Vagrant プラグインの vagrant-hostsupdater を使っているので、厳密には必要としていません。詳細については後述します。

ソースコードの取得

https://github.com/cl-lab-k/chef-serf-cluster/tree/sample_blog を clone します。

% git clone https://github.com/cl-lab-k/chef-serf-cluster -b sample_blog
Cloning into 'chef-serf-cluster'...
remote: Counting objects: 29, done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 29 (delta 0), reused 29 (delta 0), pack-reused 0
Unpacking objects: 100% (29/29), done.
Checking connectivity... done.
Note: checking out 'a29fdafe14e0acb17d08bb9c8b68d2f136e53c5e'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

% chef-serf-cluster
%

以降はこのツリー内で作業を行います。

Chef-Server VM の作成

Chef Provisioning を用いて、Chef-Server 12 用の仮想マシンを作成します。provisioning/chef-server ディレクトリに移動します。

% cd provisioning/chef-server
% ls -la
合計 16
drwxr-xr-x 2 dai dai 120  612 15:30 .
drwxr-xr-x 4 dai dai 100  612 15:30 ..
-rw-r--r-- 1 dai dai  73  612 15:30 Berksfile
-rw-r--r-- 1 dai dai 405  612 15:30 Rakefile
-rw-r--r-- 1 dai dai 971  612 15:30 chef-server.rb
-rw-r--r-- 1 dai dai 181  612 15:30 destroy.rb
%

設定は chef.json ファイルで行えますが、通常は変更する必要はないでしょう。
一連の作業は基本的に rake タスクとして定義してあります。デフォルトでは berks vendor サブコマンドを実行して chef-server Cookbook を取得し、Chef Provisioning によって Chef-Server 12 用の VirtualBox VM を Vagrant で作成します。

chef-serf-cluster-sample-chef-server

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.18)
Using chef-server-ingredient (0.4.0)
Vendoring chef-server (3.1.1) to cookbooks/chef-server
Vendoring chef-server-ingredient (0.4.0) to cookbooks/chef-server-ingredient
Vendoring packagecloud (0.0.18) to cookbooks/packagecloud
CHEF_DRIVER=vagrant chef-client -z chef-server.rb
[2015-06-12T15:54:31+09:00] WARN: No config file found or specified on command line, using command line options.
tarting Chef Client, version 12.3.0
resolving cookbooks for run list: []
Synchronizing Cookbooks:
Compiling Cookbooks...
[2015-06-12T15:54:32+09:00] WARN: Node XXXXXXXX has an empty run list.
Converging 1 resources
Recipe: @recipe_files::/tmp/chef-serf-cluster/provisioning/chef-server/chef-server.rb
  * machine[chef-server] action converge
    :
    :
    :
                  Running handlers:
                  Running handlers complete
                  Chef Client finished, 13/15 resources updated in 187.109386539 seconds
    - run 'chef-client -l auto' on chef-server

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 はありません。

Serf ノード用 VM の作成

さらに Chef Provisioning を用いて、Serf のノードとなる VM を作成します。provisioning/vms ディレクトリに移動します。

% cd ../..
% cd provisioning/vms
% ls -la
合計 8
drwxr-xr-x 2 dai dai   80  612 15:30 .
drwxr-xr-x 4 dai dai  100  612 15:30 ..
-rw-r--r-- 1 dai dai 3030  612 15:30 Rakefile
-rw-r--r-- 1 dai dai 1390  612 15:30 vms.rb
%

設定は Chef-Server 用 VM の場合と同じく chef.json ファイルで行えますが、通常は変更する必要はないでしょう。
こちらも作業は rake タスクとして定義してあります。デフォルトでは Chef-Server にて User と Organization を作成し、両者の鍵を取得、knife.rb を作成、knife ssl fetch を実行して鍵取得(参考: Chef 12の新機能: knife ssl check/fetch)、Chef Provisioning によって Serf ノード用の VirtualBox VM を Vagrant で 3台作成します。

chef-serf-cluster-sample-vms

作成した Serf ノード用 VM の Node Object は Chef-Server 12 に登録されます。Rakefile では Chef Provisioning は Chef ローカルモードを利用しています(chef-client -z)が、これはあくまで Chef Provisioning が必要としているものなので、混同しないようにしてください。

% rake
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 ssl fetch
WARNING: Certificates from chef-server.example.jp will be fetched and placed in your trusted_cert
directory (/tmp/chef-serf-cluster/.chef/trusted_certs).
    :
    :
    :
CHEF_DRIVER=vagrant chef-client -z vms.rb
[2015-06-12T16:28:02+09:00] WARN: No cookbooks directory found at or above current directory.  Assuming /tmp/chef-serf-cluster/provisioning/vms.
Starting Chef Client, version 12.3.0
resolving cookbooks for run list: []
Synchronizing Cookbooks:
Compiling Cookbooks...
[2015-06-12T16:28:03+09:00] WARN: Node testuser has an empty run list.
Converging 3 resources
Recipe: @recipe_files::/tmp/chef-serf-cluster/provisioning/vms/vms.rb
  * machine[node101] action converge
    :
    :
    :
    - run 'chef-client -l auto' on node103

Running handlers:
Running handlers complete
Chef Client finished, 3/3 resources updated in 173.498869383 seconds
  • node101 (192.168.33.101)
  • node102 (192.168.33.102)
  • node103 (192.168.33.103)

の 3台の Serf 用 VM が起動しました。

さて、これらの VM に knife ssh などからアクセスするためには、仕掛けが必要です。なぜなら、これらの VM の Attribute "ipaddress" はすべて 10.0.2.15 だからです。

本実験では vagrant-hostsupdater を用いて、ホスト側の /etc/hosts を更新するようになっています。

% tail -5 /etc/hosts
192.168.33.10  chef-server  # VAGRANT: d60dbc76afe87633bd242cc480b13aa6 (chef-server) / c8c040ff-f349-48dd-803f-a7f0ef94b223
192.168.33.10  chef-server.example.jp  # VAGRANT: d60dbc76afe87633bd242cc480b13aa6 (chef-server) / c8c040ff-f349-48dd-803f-a7f0ef94b223
192.168.33.101  node101  # VAGRANT: a0983c432e6838a69f708f6068a0f772 (node101) / 966fb052-054b-4d9b-91de-5fc38314cc4b
192.168.33.102  node102  # VAGRANT: 9226e6d398b35f9723c957b821058308 (node102) / 6b994ee1-5c04-4537-bed3-68465f1dc7c3
192.168.33.103  node103  # VAGRANT: 9425c22ebf37ecc98719c19e104cf5ed (node103) / 14175974-6183-47aa-9b7e-b3043ec64cf2
%

これにより、knife コマンドはそのまま利用可能です。

% knife ssh "name:node101" -x vagrant -P vagrant uptime
node101  07:49:49 up 21 min,  1 user,  load average: 0.00, 0.01, 0.02

もし、vagrant-hostsupdater を用いるなどして名前解決できるようにしていない場合、knife コマンドは 10.0.2.15 に接続に行ってしまいます。

% knife ssh "name:node101" -x vagrant -P vagrant hostname
WARNING: Failed to connect to 10.0.2.15 -- Errno::ETIMEDOUT: Connection timed out - connect(2) for "10.0.2.15" port 22
%

このように接続できません。eth1 の IPアドレスに対してアクセスするには -a network.interfaces.eth1.addresses.keys.rotate.first のようにする必要があります(参考: えー、これでもいけました。。。が普通にオススメできない。 `knife zero chef_client "name:*" -x vagrant --sudo -a network.interfaces.eth1.addresses.keys.rotate.first`)。しかし、Chef-DK 0.6.0 に同梱の Chef Client 12.3.0 はこの -a オプションの引数の取り扱いにバグがあり、このように指定しても接続できないのです(参考: Pass name by knife cil attribute)。

% % knife ssh "name:node101" -x vagrant -P vagrant -a network.interfaces.eth1.addresses.keys.rotate.first hostname
FATAL: 1 node found, but does not have the required attribute to establish the connection. Try setting another attribute to open the connection using --attribute.
%

この修正は Chef Client の HEAD には取り込まれていますが、12.3.0 には取り込まれていません。よって手で修正する必要があります。

% sudo cp -a /opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rb /opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rb.orig
% sudo vi /opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rb
% diff -u /opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rb.orig /opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rb
--- /opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rb.orig2015-06-12 16:44:44.584210095 +0900
+++ /opt/chefdk/embedded/apps/chef/lib/chef/knife/core/generic_presenter.rb 2015-06-12 16:45:47.427309197 +0900
@@ -181,7 +181,7 @@
             # Must check :[] before attr because spec can include
             #   `keys` - want the key named `keys`, not a list of
             #   available keys.
-            elsif data.respond_to?(:[])
+            elsif data.respond_to?(:[]) && data.kind_of?(Chef::Node)
               data = data[attr]
             elsif data.respond_to?(attr.to_sym)
               data = data.send(attr.to_sym)
%

この修正を施した後ならば、接続が可能となります。

% knife ssh "name:node101" -x vagrant -P vagrant -a network.interfaces.eth1.addresses.keys.rotate.first hostname
192.168.33.101 node101

先に述べた通り、本実験では vagrant-hostsupdater を利用しているため、この修正は厳密には必要ありません。

ポリシー

トップディレクトリに移動します。ここには Recipe、Role、Attribute 等、chef-serf-cluster Cookbook のポリシーがあります。

% cd ../..
% ls -la
合計 24
drwxr-xr-x  9 dai  dai   300  612 16:57 .
drwxrwxrwt 86 root root 1920  612 16:57 ..
drwxr-xr-x  5 dai  dai   160  612 16:28 .chef
drwxr-xr-x  8 dai  dai   280  612 16:57 .git
-rw-r--r--  1 dai  dai   126  612 15:30 .gitignore
-rw-r--r--  1 dai  dai    47  612 15:30 Berksfile
-rw-r--r--  1 dai  dai   805  612 15:30 README.md
-rw-r--r--  1 dai  dai   825  612 16:57 Rakefile
drwxr-xr-x  2 dai  dai    60  612 15:30 attributes
-rw-r--r--  1 dai  dai  1022  612 15:30 chefignore
drwxr-xr-x  3 dai  dai    60  612 15:30 files
-rw-r--r--  1 dai  dai   298  612 15:30 metadata.rb
drwxr-xr-x  4 dai  dai   100  612 15:30 provisioning
drwxr-xr-x  2 dai  dai    60  612 15:30 recipes
drwxr-xr-x  2 dai  dai    60  612 15:30 roles
%

設定は attributes/default.rbroles/chef-serf-cluster.json にあります。それぞれ serf Cookbook と sudo Cookbook の設定となります。通常は変更の必要はないでしょう。

serf 設定

default['serf']['event_handlers'] は Serf のイベントハンドラ設定のハッシュを配列として定義します。url はイベントハンドラとして実行するスクリプトのダウンロード先です。本実験ではローカルファイルシステムから取得するため、file:// としてあります。event_type はスクリプトを実行するイベントをコンマで連結した文字列です。この例では Serf クラスタに新しいメンバーが参加(member-join)、メンバーとの通信が途絶(member-failed)、メンバーが離脱(member-leave)の場合にスクリプトを実行します。詳しくは Event Handlers を参照してください。

default['serf']['version'] はインストールする Serf のバージョンを指定します。Cookbook のデフォルトでは 2013/12/5 に公開された 0.3.0 という大変古いバージョンなので必ず新しいバージョンを指定します。本実験では 0.4.x で追加された -iface (interface) や -discover といった機能を使っています。詳しくは Configuration を参照してください。

default['serf']['agent']['discover'] は Serf クラスタの名前を指定します。Serf は mDNS を利用して自動的に Serf のピアを探し出します。そのためお互いの IP アドレスを指定しなくてよいという利点があります。ただし、mDNS (マルチキャスト)が使えるネットワークであることが必要です。

default['serf']['agent']['interface'] は Serf エージェントが待ち受けするインターフェイスを指定します。先の discover はこのインターフェイスで行います。詳しくは Configuration を参照してください。本実験では Vagrant がパブリックな IP アドレスとする eth1 を指定しています。

sudo 設定

Serf Cookbook では、Serf エージェントを serf という一般ユーザの権限で動作するように設定するため、他のユーザの権限が必要な操作が行えません。本実験では、イベントハンドラで実行するスクリプト内で sudo を使って root 権限を得るようにしています。serf ユーザが sudo を介してイベントハンドラのスクリプトを実行できるように設定します。

default['authorization']['sudo']['sudoers_defaults'] では、Ubuntu 14.04 の /etc/sudoers のデフォルトと同じになるよう設定に加えて、SERF_EVENT 環境変数を保持する設定をしています。通常、sudo は指定以外の環境変数を削除するため、イベントハンドラの処理に必要な SERF_EVENT 環境変数まで消去してしまいます。これを防ぎます。sudo の設定に関しては root 権限で sudo -V を実行すると確認できます。

default['authorization']['sudo']['users'] では、serf ユーザを sudo 可能ユーザとして追加しています。

default['authorization']['sudo']['groups'] では、Ubuntu 14.04 の /etc/sudoers のデフォルトと同じになるよう設定を行っています。

default['authorization']['sudo']['passwordless'] では、パスワードを求めないように設定しています。

chef-serf-cluster Cookbook

default Recipe

files/default/sample.conf から /etc/sample.conf を作成します。このファイルが Serf イベントハンドラで更新する対象になります。
Serf イベントハンドラで Chef-Client を実行して収束を行い、ファイルを更新するのではないという点に注目してください。なぜなら、Serf クラスタに所属しているメンバーに変化があったからといって、Chef-Server が保持しているインベントリに変化があるとは限らないからです。やりようによってはそのような処理も可能でしょう。しかし本実験では簡便さのため、Serf イベントハンドラに Chef-Server を介入させないこととしました。

file:///var/lib/serf/scripts/chef-apply.sh です。Serf イベントハンドラとして実行されるスクリプトです。sudo を介して chef-apply を実行します。chef-apply は Recipe を実行するためだけの極小の Chef Client で、Chef-Server との通信は行いません。シェルスクリプトの代わりとして Chef DSL の恩恵にあずかることができます(参考: [和訳] Bashスクリプトをchef-applyに変換する)。

/var/lib/serf/scripts/update-sample-conf.rb は chef-apply が実行する Recipe です。Chef::Util を利用して /etc/sample.conf を更新します(参考: Chefのレシピでsed的な事を実施)。serf エージェントからの通知を環境変数と標準入力で受け取り、Serf クラスタに新しいメンバーが参加した場合はファイルに追加、Serf クラスタのメンバーから通信が途絶したか Serf クラスタからメンバーが離脱した場合はファイルから削除します。

ポリシーを Chef-Server アップロード

先程作成した Serf 用 Node は run_list が空のため、何も起きません。Node に適用するためのポリシーを Chef-Server にアップロードします。こちらも作業はrake タスクとして定義してあります。デフォルトでは berks vendor サブコマンド、berks upload サブコマンドを実行して Cookbook をアップロードし、knife role サブコマンドを実行して Role をアップロード、Serf 用 Node の収束を行います。この時点では run_list を設定していないため、収束を行っても Node に特に変化はありません。

% rake
berks vendor cookbooks
Resolving cookbook dependencies...
Fetching 'chef-serf-cluster' from source at .
Fetching cookbook index from https://supermarket.chef.io...
Using sudo (2.7.1)
Using serf (0.9.0)
Using chef-serf-cluster (0.1.0) from source at .
Using logrotate (1.9.1)
Vendoring chef-serf-cluster (0.1.0) to cookbooks/chef-serf-cluster
Vendoring logrotate (1.9.1) to cookbooks/logrotate
Vendoring serf (0.9.0) to cookbooks/serf
Vendoring sudo (2.7.1) to cookbooks/sudo
berks upload --no-ssl-verify --force
Uploaded chef-serf-cluster (0.1.0) to: 'https://chef-server.example.jp:443/organizations/testorg'
Uploaded logrotate (1.9.1) to: 'https://chef-server.example.jp:443/organizations/testorg'
Uploaded serf (0.9.0) to: 'https://chef-server.example.jp:443/organizations/testorg'
Uploaded sudo (2.7.1) to: 'https://chef-server.example.jp:443/organizations/testorg'
knife role from file roles/chef-serf-cluster.json
Updated Role chef-serf-cluster!
knife ssh 'name:*' -x vagrant -P vagrant 'sudo chef-client'
node101 Starting Chef Client, version 12.3.0
node103 Starting Chef Client, version 12.3.0
node102 Starting Chef Client, version 12.3.0
node101 resolving cookbooks for run list: []
node103 resolving cookbooks for run list: []
node101 Synchronizing Cookbooks:
node101 Compiling Cookbooks...
node101 [2015-06-12T08:44:24+00:00] WARN: Node node101 has an empty run list.
node101 Converging 0 resources
node101
node101 Running handlers:
node101 Running handlers complete
node101 Chef Client finished, 0/0 resources updated in 1.267921461 seconds
node103 Synchronizing Cookbooks:
node103 Compiling Cookbooks...
node103 [2015-06-12T08:44:24+00:00] WARN: Node node103 has an empty run list.
node103 Converging 0 resources
node103
node103 Running handlers:
node103 Running handlers complete
node103 Chef Client finished, 0/0 resources updated in 1.315651996 seconds
node102 resolving cookbooks for run list: []
node102 Synchronizing Cookbooks:
node102 Compiling Cookbooks...
node102 [2015-06-12T08:44:29+00:00] WARN: Node node102 has an empty run list.
node102 Converging 0 resources
node102
node102 Running handlers:
node102 Running handlers complete
node102 Chef Client finished, 0/0 resources updated in 6.391368714 seconds
%

Serf 用 VM にポリシーを適用

では、Serf 用 VM に 1つずつポリシーを適用していきます。

% knife node run_list add node101 "role[chef-serf-cluster]"
node101
:
  run_list
: role[chef-serf-cluster]

適用したら、収束を行います。

% rake converge
knife ssh 'name:*' -x vagrant -P vagrant 'sudo chef-client'
node103 Starting Chef Client, version 12.3.0
node101 Starting Chef Client, version 12.3.0
node102 Starting Chef Client, version 12.3.0
node102 resolving cookbooks for run list: []
node101 resolving cookbooks for run list: ["sudo", "chef-serf-cluster", "serf"]
node102 Synchronizing Cookbooks:
node102 Compiling Cookbooks...
node102 [2015-06-12T08:46:55+00:00] WARN: Node node102 has an empty run list.
node102 Converging 0 resources
node102
node102 Running handlers:
node102 Running handlers complete
node102 Chef Client finished, 0/0 resources updated in 1.317966938 seconds
node101 Synchronizing Cookbooks:
node101   - sudo
node101   - chef-serf-cluster
node101   - serf
node101   - logrotate
node101 Compiling Cookbooks...
node101 Converging 27 resources
node101 Recipe: sudo::default
    :
    :
    :
node101 Running handlers:
node101 Running handlers complete
node101 Chef Client finished, 27/29 resources updated in 17.392931293 seconds

VM を確認してみます。

% rake serf_members
knife ssh 'name:*' -x vagrant -P vagrant 'serf members'
node101 node101  192.168.33.101:7946  alive
node102 bash: serf: command not found
node103 bash: serf: command not found
rake aborted!
Command failed with status (127): [knife ssh 'name:*' -x vagrant -P vagrant '...]
/tmp/chef-serf-cluster/Rakefile:38:in `block in <top (required)>'

Tasks: TOP => serf_members
(See full trace by running task with --trace)
% rake sample_conf
knife ssh 'name:*' -x vagrant -P vagrant 'cat /etc/sample.conf'
node101 server {
node101     server 192.168.33.101;
node101     #server
node101 }
node102 cat: /etc/sample.conf: No such file or directory
node103 cat: /etc/sample.conf: No such file or directory
rake aborted!
Command failed with status (1): [knife ssh 'name:*' -x vagrant -P vagrant '...]
/tmp/chef-serf-cluster/Rakefile:43:in `block in <top (required)>'

Tasks: TOP => sample_conf
(See full trace by running task with --trace)

まず、node101 のみが Serf クラスタのメンバーとなっていて、/etc/sample.conf ファイルにも node101 のみが記載されています。

chef-serf-cluster-sample-install-1

次に node102 にポリシーを適用します。

% knife node run_list add node102 "role[chef-serf-cluster]"
node102
:
  run_list
: role[chef-serf-cluster]
% rake converge
knife ssh 'name:*' -x vagrant -P vagrant 'sudo chef-client'
node101 Starting Chef Client, version 12.3.0
node102 Starting Chef Client, version 12.3.0
node103 Starting Chef Client, version 12.3.0
node102 resolving cookbooks for run list: ["sudo", "chef-serf-cluster", "serf"]
node102 Synchronizing Cookbooks:
node102   - sudo
node102   - chef-serf-cluster
node102   - serf
node102   - logrotate
node102 Compiling Cookbooks...
node102 Converging 27 resources
node102 Recipe: sudo::default
    :
    :
    :
node102 Running handlers:
node102 Running handlers complete
node102 Chef Client finished, 27/29 resources updated in 18.963169116 seconds

VM を確認します。

% LC_ALL=C TERM=xterm-color rake serf_members
knife ssh 'name:*' -x vagrant -P vagrant 'serf members'
node103 bash: serf: command not found
node102 node102  192.168.33.102:7946  alive  
node102 node101  192.168.33.101:7946  alive
node101 node101  192.168.33.101:7946  alive  
node101 node102  192.168.33.102:7946  alive
rake aborted!
Command failed with status (127): [knife ssh 'name:*' -x vagrant -P vagrant '...]
/tmp/chef-serf-cluster/Rakefile:38:in `block in <top (required)>'

Tasks: TOP => serf_members
(See full trace by running task with --trace)
% rake sample_conf
knife ssh 'name:*' -x vagrant -P vagrant 'cat /etc/sample.conf'
node103 cat: /etc/sample.conf: No such file or directory
node102 server {
node102     server 192.168.33.102;
node102     server 192.168.33.101;
node102     #server
node102 }
node101 server {
node101     server 192.168.33.101;
node101     server 192.168.33.102;
node101     #server
node101 }
rake aborted!
Command failed with status (1): [knife ssh 'name:*' -x vagrant -P vagrant '...]
/tmp/chef-serf-cluster/Rakefile:43:in `block in <top (required)>'

Tasks: TOP => sample_conf
(See full trace by running task with --trace)

node102 も追加されました。なお、/etc/sample.conf の更新は chef-client コマンドの収束によって行われたのではありません。Serf イベントハンドラによって呼び出された chef-apply コマンドによって行われています。事実、chef-client コマンドによって適用されるポリシーはファイルを置くだけで、chef-apply コマンドによって適用されるポリシーがファイルを更新します。

chef-serf-cluster-sample-install-2

node103 にもポリシーを適用します。

% knife node run_list add node103 "role[chef-serf-cluster]"
node103
:
  run_list
: role[chef-serf-cluster]
% rake converge
knife ssh 'name:*' -x vagrant -P vagrant 'sudo chef-client'
node101 Starting Chef Client, version 12.3.0
node103 Starting Chef Client, version 12.3.0
node102 Starting Chef Client, version 12.3.0
node103 resolving cookbooks for run list: ["sudo", "chef-serf-cluster", "serf"]
node103 Synchronizing Cookbooks:
node103   - chef-serf-cluster
node103   - serf
node103   - logrotate
node103 Compiling Cookbooks...
node103 Converging 27 resources
node103 Recipe: sudo::default
    :
    :
    :
node103 Running handlers:
node103 Running handlers complete
node103 Chef Client finished, 27/29 resources updated in 17.828711263 seconds
%

node103 も追加されました。

% rake serf_members              
knife ssh 'name:*' -x vagrant -P vagrant 'serf members'
node101 node103  192.168.33.103:7946  alive  
node101 node101  192.168.33.101:7946  alive  
node101 node102  192.168.33.102:7946  alive
node103 node101  192.168.33.101:7946  alive  
node103 node102  192.168.33.102:7946  alive  
node103 node103  192.168.33.103:7946  alive
node102 node102  192.168.33.102:7946  alive  
node102 node101  192.168.33.101:7946  alive  
node102 node103  192.168.33.103:7946  alive
% rake sample_conf              
knife ssh 'name:*' -x vagrant -P vagrant 'cat /etc/sample.conf'
node103 server {
node103     server 192.168.33.101;
node103     server 192.168.33.102;
node103     server 192.168.33.103;
node103     #server
node103 }
node102 server {
node102     server 192.168.33.102;
node102     server 192.168.33.101;
node102     server 192.168.33.103;
node102     #server
node102 }
node101 server {
node101     server 192.168.33.101;
node101     server 192.168.33.102;
node101     server 192.168.33.103;
node101     #server
node101 }
%

chef-serf-cluster-sample-install-3

Serf 用 VM の停止と復帰

試しに node102 を halt してみます。

% vagrant halt node102
==> node102: Removing cache buckets symlinks...
==> node102: Attempting graceful shutdown of VM...
==> node102: Removing hosts
%

VM を確認します。

% rake serf_members
knife ssh 'name:*' -x vagrant -P vagrant 'serf members'
WARNING: Failed to connect to node102 -- SocketError: getaddrinfo: Name or service not known
node101 node101  192.168.33.101:7946  alive  
node101 node102  192.168.33.102:7946  left  
node101 node103  192.168.33.103:7946  alive
node103 node103  192.168.33.103:7946  alive  
node103 node101  192.168.33.101:7946  alive  
node103 node102  192.168.33.102:7946  left
% rake sample_conf
knife ssh 'name:*' -x vagrant -P vagrant 'cat /etc/sample.conf'
WARNING: Failed to connect to node102 -- SocketError: getaddrinfo: Name or service not known
node103 server {
node103     server 192.168.33.101;
node103     server 192.168.33.103;
node103     #server
node103 }
node101 server {
node101     server 192.168.33.101;
node101     server 192.168.33.103;
node101     #server
node101 }

node102 は Serf クラスタから離脱した left ステータスとなり、/etc/sample.conf からも削除されました。

node102 を up します。

% vagrant up node102
Bringing machine 'node102' up with 'virtualbox' provider...
==> node102: Checking if box 'chef/ubuntu-14.04' is up to date...
==> node102: Clearing any previously set forwarded ports...
==> node102: Fixed port collision for 22 => 2222. Now on port 2201.
==> node102: Clearing any previously set network interfaces...
==> node102: Preparing network interfaces based on configuration...
    node102: Adapter 1: nat
    node102: Adapter 2: hostonly
==> node102: Forwarding ports...
    node102: 22 => 2201 (adapter 1)
==> node102: Running 'pre-boot' VM customizations...
==> node102: Booting VM...
==> node102: Waiting for machine to boot. This may take a few minutes...
    node102: SSH address: 127.0.0.1:2201
    node102: SSH username: vagrant
    node102: SSH auth method: private key
    node102: Warning: Connection timeout. Retrying...
==> node102: Machine booted and ready!
==> node102: Checking for guest additions in VM...
==> node102: Checking for host entries
==> node102: adding to (/etc/hosts) : 192.168.33.102  node102  # VAGRANT: 9226e6d398b35f9723c957b821058308 (node102) / 6b994ee1-5c04-4537-bed3-68465f1dc7c3
==> node102: Setting hostname...
==> node102: Configuring and enabling network interfaces...
==> node102: Mounting shared folders...
    node102: /vagrant => /tmp/chef-serf-cluster/.chef/vms
    node102: /tmp/vagrant-cache => /var/local/kitchen/vagrant/cache/chef/ubuntu-14.04
==> node102: Configuring cache buckets...
==> node102: Skipping Yum cache bucket as the guest machine does not support it
==> node102: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> node102: to force provisioning. Provisioners marked to run always will still run.
%

VM を確認します。

% rake serf_members
knife ssh 'name:*' -x vagrant -P vagrant 'serf members'
node101 node101  192.168.33.101:7946  alive  
node101 node102  192.168.33.102:7946  alive  
node101 node103  192.168.33.103:7946  alive
node102 node101  192.168.33.101:7946  alive  
node102 node102  192.168.33.102:7946  alive  
node102 node103  192.168.33.103:7946  alive
node103 node103  192.168.33.103:7946  alive  
node103 node101  192.168.33.101:7946  alive  
node103 node102  192.168.33.102:7946  alive
%
% rake sample_conf
knife ssh 'name:*' -x vagrant -P vagrant 'cat /etc/sample.conf'
node101 server {
node101     server 192.168.33.101;
node101     server 192.168.33.103;
node101     server 192.168.33.102;
node101     #server
node101 }
node103 server {
node103     server 192.168.33.101;
node103     server 192.168.33.103;
node103     server 192.168.33.102;
node103     #server
node103 }
node102 server {
node102     server 192.168.33.102;
node102     server 192.168.33.103;
node102     server 192.168.33.101;
node102     #server
node102 }
%

node102 が Serf クラスタに復帰し、/etc/sample.conf に追加されました。ファイルの更新はすべて Serf イベントハンドラから呼び出された chef-apply によって行われています。

chef-serf-cluster-sample-serf

まとめ

本稿では、Chef ProvisioningとVagrant (VirtualBox)を用いて、非常に簡単な Serf クラスタを作成してみました。Chef Provisioning を使った Chef-Server/Client 環境の作成、Serf クラスタの動作、chef-apply の活用例について、概要をつかんでいただけたと思います。

当初は Nginx によるロードバランサを作成する予定だった実験は、簡便のためにかなり縮小し、Serf クラスタはノードがすべて対等となりました。/etc/sample.conf ファイルの内容は当初の計画のなごりです。Serf ノードの役割を個別に割り当てれば、そのような動作も可能となるでしょう。また本文中でも述べた通り、Serf イベントハンドラとして chef-client コマンドを起動する方法については仕組みが複雑になるため断念しました。Serf から chef-client を起動して収束を行うためのよい方法がないかは今後の課題です。

参考文献

Chef-Provisioning

Serf

Chef

CL LAB Mail Magazine

CL LABの情報を逃さずチェックしよう!

メールアドレスを登録すると記事が投稿されるとメールで通知します。

メールアドレス: 登録

※登録後メールに記載しているリンクをクリックして認証してください。

Related post