fbpx

CL LAB

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

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

 ★ 16

はじめに

本稿では、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  629 18:01 .chef/
drwxr-xr-x  8 dai  dai   300  7月  1 12:51 .git/
-rw-r--r--  1 dai  dai   177  630 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  630 15:53 Vagrantfile
-rw-r--r--  1 dai  dai  1114  630 12:11 chefignore
-rw-r--r--  1 dai  dai   324  7月  1 12:47 metadata.rb
drwxr-xr-x  3 dai  dai    60  630 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

CL LAB Mail Magazine

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

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

メールアドレス: 登録

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

Related post