fbpx

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

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

はじめに

本稿では、Chef Provisioning と Docker を用いて Serf クラスタを作成してみます。なお、Serf クラスタの挙動については深く掘り下げず、Chef Provisioning と Docker の利用例を主目的とします。本稿で使用したソースコードはすべて https://github.com/cl-lab-k/chef-serf-docker-cluster にあります。

なお、Chef Provisioning と Docker の組み合わせとして knife-container がありましたがプロジェクト終了しており、現在は chef-provisioning-docker の利用が推奨されています。

Chef Provisioning とは

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

Docker とは

Docker は米 Docker 社が開発する Linux コンテナ管理ソフトウェアです。さまざまな既存ソフトウェアを組み合わせて、アプリケーションとその依存関係にあるものをパッケージングする方法を提供します。

Serf とは

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

事前準備

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

ソースコードの取得

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


% git clone https://github.com/cl-lab-k/chef-serf-docker-cluster -b sample_blog
Cloning into 'chef-serf-docker-cluster'...
:
% cd chef-serf-docker-cluster
%

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

VM の作成

Vagrant を用いて、今回の実験用の仮想マシンを作成します。


% ls -la
合計 28
drwxr-xr-x 6 dai dai 260 7月 1 12:50 ./
drwxrwxrwt 29 root root 780 7月 1 12:51 ../
drwxr-xr-x 2 dai dai 60 6月 29 18:01 .chef/
drwxr-xr-x 8 dai dai 300 7月 1 12:51 .git/
-rw-r--r-- 1 dai dai 177 6月 30 13:26 .gitignore
-rw-r--r-- 1 dai dai 47 7月 1 12:47 Berksfile
-rw-r--r-- 1 dai dai 818 7月 1 12:51 README.md
-rw-r--r-- 1 dai dai 598 7月 1 12:49 Rakefile
-rw-r--r-- 1 dai dai 483 6月 30 15:53 Vagrantfile
-rw-r--r-- 1 dai dai 1114 6月 30 12:11 chefignore
-rw-r--r-- 1 dai dai 324 7月 1 12:47 metadata.rb
drwxr-xr-x 3 dai dai 60 6月 30 18:26 provisioning/
drwxr-xr-x 2 dai dai 60 7月 1 11:10 recipes/
%

作成する VM の設定は Vagrantfile ファイルで行えます。初期設定では、Box は chef/ubuntu-14.04、IP アドレスは 192.168.33.101、メモリは 4096M の設定となっています。一連の作業は基本的に rake タスクとして定義してあります。デフォルトでは berks vendor サブコマンドを実行して chef-dk Cookbook と docker Cookbook を取得し、Vagrant によって VirtualBox VM を作成します。起動した VM には Chef Zero Provisioner を用いて chef-serf-docker-cluster::default Recipe を適用し、Docker のインストールと起動、vagrant ユーザの所属グループの変更、chef-provisioning-docker のインストールを行い、Chef Provisioner Docker 用のファイルを VM に転送します。


% rake
berks vendor cookbooks
Resolving cookbook dependencies...
Fetching 'chef-serf-docker-cluster' from source at .
Fetching cookbook index from https://supermarket.chef.io...
Using chef-dk (3.1.0)
Using chef-serf-docker-cluster (0.1.0) from source at .
Using dmg (2.2.2)
Using docker (0.40.0)
Vendoring chef-dk (3.1.0) to cookbooks/chef-dk
Vendoring chef-serf-docker-cluster (0.1.0) to cookbooks/chef-serf-docker-cluster
Vendoring dmg (2.2.2) to cookbooks/dmg
Vendoring docker (0.40.0) to cookbooks/docker
vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'chef/ubuntu-14.04'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'chef/ubuntu-14.04' is up to date...
==> default: Setting the name of the VM: chef-serf-docker-cluster_default_1435722731564_70369
:
:
:
==> default: Running provisioner: chef_zero...
default: Installing Chef (latest)...
Generating chef JSON and uploading...
==> default: Running chef-zero...
==> default: stdin: is not a tty
==> default: [2015-07-01T03:53:25+00:00] INFO: Started chef-zero at chefzero://localhost:8889 with repository at /tmp/vagrant-chef/abb1ed29161e26e71af16852033b75af
:
:
:
scp -i /tmp/chef-serf-docker-cluster/.vagrant/machines/default/virtualbox/private_key -P 2222 -r /tmp/chef-serf-docker-cluster/provisioning/docker vagrant@127.0.0.1:
Berksfile 100% 54 0.1KB/s 00:00
docker.rb 100% 731 0.7KB/s 00:00
Rakefile 100% 1022 1.0KB/s 00:00
%

VM 内で Chef Provisioning Docker を実行

作成した VM にログインします。


% vagrant ssh
Welcome to Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-24-generic x86_64)


* Documentation: https://help.ubuntu.com/
Last login: Tue Oct 21 14:52:42 2014 from 10.0.2.2
vagrant@vagrant:~$

先程 VM に scp したディレクトリがあるので、そちらに移動します。


vagrant@vagrant:~$ cd docker
vagrant@vagrant:~/docker$ ls -la
total 20
drwxr-xr-x 2 vagrant vagrant 4096 Jul 1 03:55 .
drwxr-xr-x 5 vagrant vagrant 4096 Jul 1 03:55 ..
-rw-r--r-- 1 vagrant vagrant 54 Jul 1 03:55 Berksfile
-rw-r--r-- 1 vagrant vagrant 1022 Jul 1 03:55 Rakefile
-rw-r--r-- 1 vagrant vagrant 731 Jul 1 03:55 docker.rb
vagrant@vagrant:~/docker$

ここでは chef-provisioning-docker を用いて、Docker 社の公式レポジトリの ubuntu:14.04 イメージから Serf 用イメージを作成し、それを基に 5つ Serf 用コンテナを起動します。起動した Serf 用コンテナは自動的にクラスタを構成します。

なお、この chef-serf-docker-cluster/provisioning/docker は VM 内でなくとも実機上で実行が可能ですので、興味があれば各自試してみてください。

こちらも作業は rake タスクとして定義してあります。ただし、この VM には Ubuntu 公式の rake パッケージが入っていないため、代わりに chef-dk 同梱の /opt/chefdk/embedded/bin/rake を実行してください。


vagrant@vagrant:~/docker$ /opt/chefdk/embedded/bin/rake
berks vendor cookbooks
Resolving cookbook dependencies...
Fetching cookbook index from https://supermarket.chef.io...
Installing logrotate (1.9.2)
Installing serf (0.9.0)
Vendoring logrotate (1.9.2) to cookbooks/logrotate
Vendoring serf (0.9.0) to cookbooks/serf

まず Berkshelf で必要な serf Cookbook の取得を行っています。


CHEF_DRIVER=docker chef-client -z docker.rb
[2015-07-01T06:37:17+00:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 12.3.0
resolving cookbooks for run list: []
Synchronizing Cookbooks:
Compiling Cookbooks...
[2015-07-01T06:37:18+00:00] WARN: Node vagrant.vm has an empty run list.
Converging 6 resources
Recipe: @recipe_files::/home/vagrant/docker/docker.rb
* machine_image[serf] action create
- create node serf at chefzero://localhost:8889
- add normal.serf = {"version"=>"0.6.4", "agent"=>{"discover"=>"docker"}}
- add normal.tags = nil
- add normal.chef_provisioning = {"reference"=>{"driver_url"=>"docker:unix:///var/run/docker.sock", "driver_version"=>"0.7", "allocated_at"=>"2015-07-01 06:37:18 UTC", "host_node"=>"chefzero://localhost:8889/nodes/", "container_name"=>"serf", "image_id"=>nil, "docker_options"=>{:base_image=>{:name=>"ubuntu", :repository=>"ubuntu", :tag=>"14.04"}}}}
- update run_list from [] to ["recipe[serf::default]"]
- update node serf at chefzero://localhost:8889
- add normal.chef_provisioning.reference.docker_options.base_image = {:name=>"ubuntu", :repository=>"ubuntu", :tag=>"14.04"}
- remove normal.chef_provisioning.reference.docker_options.base_image
- add normal.chef_provisioning.reference.container_id = "92528fce3e3e8c4933d5062770ea2ff39339fd1a5138ddf643f042c0fe7aabb0"
- generate private key (2048 bits)
- create directory /etc/chef on serf
- write file /etc/chef/client.pem on serf
- create client serf at clients
:
- update node serf at chefzero://localhost:8889
- add normal.chef_provisioning.reference.docker_options.base_image = {:name=>"ubuntu", :repository=>"ubuntu", :tag=>"14.04"}
- remove normal.chef_provisioning.reference.docker_options.base_image
- write file /etc/chef/client.rb on serf
- write file /tmp/detect.sh on serf
- create new file /home/vagrant/.chef/package_cache/chef_12.4.0-1_amd64.deb
- update content in file /home/vagrant/.chef/package_cache/chef_12.4.0-1_amd64.deb from none to 2d66c2
- (file sizes exceed 10000000 bytes, diff output suppressed)
- upload file /home/vagrant/.chef/package_cache/chef_12.4.0-1_amd64.deb to /tmp/chef_12.4.0-1_amd64.deb on serf
- run 'dpkg -i "/tmp/chef_12.4.0-1_amd64.deb"' on serf
- update node serf at chefzero://localhost:8889
- add normal.chef_provisioning.reference.docker_options.base_image = {:name=>"ubuntu", :repository=>"ubuntu", :tag=>"14.04"}
- remove normal.chef_provisioning.reference.docker_options.base_image
- run 'chef-client -l auto' on serf
- create data bag machine_image at chefzero://localhost:8889
- create data bag item serf at chefzero://localhost:8889
- add reference = {"driver_url"=>"docker:unix:///var/run/docker.sock", "driver_version"=>"0.7", "allocated_at"=>1435732754, :docker_options=>{:base_image=>{:name=>"chef_serf", :repository=>"chef", :tag=>"serf"}, :from_image=>true}}
- add run_list = ["recipe[serf::default]"]
- delete node serf at chefzero://localhost:8889

chef-provisioning-docker を利用して、Serf 用の Docker イメージを作成します。この際、Cookbook の適用には Chef-Zero を用いています。


* machine[serf101] action converge
- create node serf101 at chefzero://localhost:8889
- add normal.tags = nil
- add normal.chef_provisioning = {"reference"=>{"driver_url"=>"docker:unix:///var/run/docker.sock", "driver_version"=>"0.7", "allocated_at"=>"2015-07-01 06:39:14 UTC", "host_node"=>"chefzero://localhost:8889/nodes/", "container_name"=>"serf101", "image_id"=>nil, "docker_options"=>{:command=>"/usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json"}}, "from_image"=>"serf"}
- update node serf101 at chefzero://localhost:8889
- add normal.chef_provisioning.reference.docker_options.command = "/usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json"
- remove normal.chef_provisioning.reference.docker_options.command
- add normal.chef_provisioning.reference.container_id = "0d30ec1cade296c551f3e10e04dd87155cc8ef0619251970e326c6ab5c319717"
- create client serf101 at clients
:
- update node serf101 at chefzero://localhost:8889
- add normal.chef_provisioning.reference.docker_options.command = "/usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json"
- remove normal.chef_provisioning.reference.docker_options.command
- write file /etc/chef/client.rb on serf101
- update node serf101 at chefzero://localhost:8889
- add normal.chef_provisioning.reference.docker_options.command = "/usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json"
- remove normal.chef_provisioning.reference.docker_options.command
- run 'chef-client -l auto' on serf101

引き続き、chef-provisioning-docker を利用して、Serf 用の Docker イメージからコンテナを作成していきます。ここでも Chef-Zero を活用しています。


:
:
:
Running handlers:
Running handlers complete
Chef Client finished, 6/6 resources updated in 147.028399848 seconds
vagrant@vagrant:~/docker$

5つのコンテナを起動し終わりました。なお、ここではコンテナを並列で作成する machine_batch を利用していません。競合が発生するのか、コンテナをうまく作成できないためです。

Docker コンテナの確認

起動した Docker コンテナの状態を確認してみましょう。


vagrant@vagrant:~/docker$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
50cef5723d6b 1d0fdba605f4a6586e71cc6f44a614dcd4c4ea050f2570e5e6ad6113b46831c1:latest "/usr/bin/serf agent 5 minutes ago Up 5 minutes serf105
6a1933e26dd8 5cd3d1fca06db403b5c094404816171657db2b8b05941d41e89f6966813ba3ef:latest "/usr/bin/serf agent 5 minutes ago Up 5 minutes serf104
4937c32cfdb8 c2373783c2391c00dfe2d3781db09e1cc37ef5776d47c0d2714152c27ac09606:latest "/usr/bin/serf agent 5 minutes ago Up 5 minutes serf103
093f23862636 537610a1963c31bbb84b654be8ab2fbcd8aebc286b645bd1a952161b5d5de358:latest "/usr/bin/serf agent 5 minutes ago Up 5 minutes serf102
547ae9fa3ca6 f05b9c1c058c0be2d2f94c7dc11eccf52389994352deeeeb7948ae5ab4515f17:latest "/usr/bin/serf agent 5 minutes ago Up 5 minutes serf101
vagrant@vagrant:~/docker$


vagrant@vagrant:~/docker$ ps auxwwwf | tail -6
root 2234 1.4 0.5 760480 21208 ? Ssl 06:35 0:08 /usr/bin/docker -d --ip-forward=true --log-level=info --tls=true
root 4395 0.2 0.1 13732 7564 ? Ssl 06:39 0:00 \_ /usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json
root 4934 0.2 0.1 13732 6968 ? Ssl 06:39 0:00 \_ /usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json
root 5463 0.2 0.1 13732 7404 ? Ssl 06:39 0:00 \_ /usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json
root 6010 0.2 0.1 13732 7164 ? Ssl 06:39 0:00 \_ /usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json
root 6551 0.2 0.1 13732 6944 ? Ssl 06:39 0:00 \_ /usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json
vagrant@vagrant:~/docker$

このように、Serf 用コンテナが 5つ起動しています。

コンテナ内で serf members を行う rake タスクを用意してあるので、実行してみます。


vagrant@vagrant:~/docker$ /opt/chefdk/embedded/bin/rake members
docker exec 50cef5723d6b serf members
6a1933e26dd8 172.17.0.45:7946 alive
093f23862636 172.17.0.29:7946 alive
547ae9fa3ca6 172.17.0.21:7946 alive
50cef5723d6b 172.17.0.53:7946 alive
4937c32cfdb8 172.17.0.37:7946 alive
docker exec 6a1933e26dd8 serf members
6a1933e26dd8 172.17.0.45:7946 alive
093f23862636 172.17.0.29:7946 alive
547ae9fa3ca6 172.17.0.21:7946 alive
4937c32cfdb8 172.17.0.37:7946 alive
50cef5723d6b 172.17.0.53:7946 alive
docker exec 4937c32cfdb8 serf members
4937c32cfdb8 172.17.0.37:7946 alive
093f23862636 172.17.0.29:7946 alive
547ae9fa3ca6 172.17.0.21:7946 alive
6a1933e26dd8 172.17.0.45:7946 alive
50cef5723d6b 172.17.0.53:7946 alive
docker exec 093f23862636 serf members
4937c32cfdb8 172.17.0.37:7946 alive
6a1933e26dd8 172.17.0.45:7946 alive
50cef5723d6b 172.17.0.53:7946 alive
093f23862636 172.17.0.29:7946 alive
547ae9fa3ca6 172.17.0.21:7946 alive
docker exec 547ae9fa3ca6 serf members
4937c32cfdb8 172.17.0.37:7946 alive
6a1933e26dd8 172.17.0.45:7946 alive
50cef5723d6b 172.17.0.53:7946 alive
547ae9fa3ca6 172.17.0.21:7946 alive
093f23862636 172.17.0.29:7946 alive
vagrant@vagrant:~/docker$

このように、Serf クラスタが構成されています。

手動で 1つ Serf コンテナを追加してみましょう。
まず、chef-zero を別ターミナルからフォアグラウンドで起動しておきます。


vagrant@vagrant:~/docker$ /opt/chefdk/embedded/bin/chef-zero --host 172.17.42.1
>> Starting Chef Zero (v4.2.2)...
>> WEBrick (v1.3.1) on Rack (v1.6.1) is listening at http://172.17.42.1:8889
>> Press CTRL+C to stop


別のターミナルで docker run を実行します。
--name=serf191 はコンテナの名前を指定、--detach はバックグラウンドで実行、chef:serf は利用するイメージ、/usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json はコンテナで実行するコマンドです。


vagrant@vagrant:~/docker$ docker run --name=serf191 --detach chef:serf /usr/bin/serf agent -config-file /opt/serf/config/serf_agent.json
1d0d56f27a73e8e73d5eabe7499c04a2a80676b28ec57c1e67930bd3b455c955
vagrant@vagrant:~/docker$

先程のように rake members で Serf クラスタメンバを確認してみます。


vagrant@vagrant:~/docker$ /opt/chefdk/embedded/bin/rake members
:
docker exec 547ae9fa3ca6 serf members
1d0d56f27a73 172.17.0.59:7946 alive
547ae9fa3ca6 172.17.0.21:7946 alive
093f23862636 172.17.0.29:7946 alive
4937c32cfdb8 172.17.0.37:7946 alive
6a1933e26dd8 172.17.0.45:7946 alive
50cef5723d6b 172.17.0.53:7946 alive
vagrant@vagrant:~/docker$

このように今起動したコンテナによってメンバが 1つ増えていることがわかります。

コンテナを停止し、


vagrant@vagrant:~/docker$ docker stop 1d0d56f27a73e8e73d5eabe7499c04a2a80676b28ec57c1e67930bd3b455c955
1d0d56f27a73e8e73d5eabe7499c04a2a80676b28ec57c1e67930bd3b455c955
vagrant@vagrant:~/docker$

クラスタメンバを確認します。


vagrant@vagrant:~/docker$ /opt/chefdk/embedded/bin/rake members
:
docker exec 547ae9fa3ca6 serf members
50cef5723d6b 172.17.0.53:7946 alive
1d0d56f27a73 172.17.0.59:7946 failed
547ae9fa3ca6 172.17.0.21:7946 alive
093f23862636 172.17.0.29:7946 alive
4937c32cfdb8 172.17.0.37:7946 alive
6a1933e26dd8 172.17.0.45:7946 alive
vagrant@vagrant:~/docker$

failed と検出されています。

停止したコンテナを再起動し、


vagrant@vagrant:~/docker$ docker start 1d0d56f27a73e8e73d5eabe7499c04a2a80676b28ec57c1e67930bd3b455c955
1d0d56f27a73e8e73d5eabe7499c04a2a80676b28ec57c1e67930bd3b455c955
vagrant@vagrant:~/docker$

クラスタメンバを確認します。


vagrant@vagrant:~/docker$ /opt/chefdk/embedded/bin/rake members
:
docker exec 547ae9fa3ca6 serf members
1d0d56f27a73 172.17.0.60:7946 alive
547ae9fa3ca6 172.17.0.21:7946 alive
093f23862636 172.17.0.29:7946 alive
4937c32cfdb8 172.17.0.37:7946 alive
6a1933e26dd8 172.17.0.45:7946 alive
50cef5723d6b 172.17.0.53:7946 alive
vagrant@vagrant:~/docker$

元通り alive となってクラスタに復帰していることがわかります。

まとめ

本稿では、chef-provisioning-docker を用いて Serf クラスタを作成してみました。Serf ノード 1つにつき 1VM を使う方法に比べて、Docker を用いると非常に軽量かつ高速に Serf クラスタを作成できることがつかんでいただけたと思います。

本実験ではイベントハンドリングを行わない簡単な Serf クラスタ環境の作成のみを行いました。また、Chef-Server ではなく Chef-Zero ですべてを賄っています。イベントハンドラや Chef-Server の利用は今後の課題です。

参考文献

関連記事

Docker

Serf

Author

Chef・Docker・Mirantis製品などの技術要素に加えて、会議の進め方・文章の書き方などの業務改善にも取り組んでいます。「Chef活用ガイド」共著のほか、Debian Official Developerもやっています。

Daisuke Higuchiの記事一覧

新規CTA