ようへいの日々精進XP

よかろうもん

今更だけど capistrano と chef-solo を組み合わせて複数のホストをセットアップする

はじめに

  • knife-solo で一台のホストをセットアップすることは出来ても同時に複数のホストをセットアップするのはちと難しい
  • でも capistranochef-solo を使えば同時に複数のホストをセットアップすることは出来そう
  • ということで今更だけど capistranochef-solo を組み合わせてみる
  • セットアップ後の確認は serverspec を使って確認する

早速試してみる

若干、課題はあるものの以下のような capistrano のレシピを使うことで実現出来た。

レシピ(chef のレシピでは無くて...)

以下のレシピを適当なファイル名で保存(例では setup.rb)する。

role :servers, "",""
#
set :user, ""
set :path_to, ""
#
set :chef_local_dir, "#{path_to}/chef-repo"
set :chef_remote_dir, ""
#
namespace :chef do
  task :init, :roles => :servers do
    run "apt-get update && apt-get -y install sudo curl rsync"
    run "curl -L https://www.opscode.com/chef/install.sh | sudo bash"
  end
  task :sync, :roles => :servers do
    run "mkdir -p #{chef_remote_dir}/chef-repo/"
    find_servers_for_task(current_task).each do |server|
      if ( "#{server.port}" == nil )
        `rsync -avz #{chef_local_dir}/ -e "ssh -p #{server.port}" root@#{server.host}:#{chef_remote_dir}/chef-repo/`
      else
        `rsync -avz #{chef_local_dir}/ #{user}@#{server.host}:#{chef_remote_dir}/chef-repo/`
      end
    end
  end
  task :deploy, :roles => :servers do
    find_servers_for_task(current_task).each do |server|
      run "chef-solo -j #{chef_remote_dir}/chef-repo/nodes/localhost.json -c #{chef_remote_dir}/chef-repo/solo.rb"
    end
  end
end

ソースはこちら

使い方

まず、以下を実行すると対象のノードに Omnibus installerchef クライアントがインストールされる。

cap setup chef:init

taskinit が実行される。但し、この init は残念ながら apt-get が処理として走るので DebianUbuntu 限定になってしまっている。これは何らかの方法で OS の判定を入れて処理を分岐する必要がある。*1

次に :sync で、ローカルホストの chef-reporsync で対象ホストに丸っとコピーされる。

cap setup chef:sync

次に以下を実行すると対象ノードで cookbook が適用される。

cap setup chef:deploy

run_list が書かれた localhost.json ファイルを利用して cookbook が適用されることになる。また、find_servers_for_taskrole に書かれたホストが適用されることになる。(ホスト名だけを取り出す場合には server.host でポート番号を取り出す場合には server.port を使う)

demo

docker コンテナ二台に対してこちらcookbook を適用してみる。手順は上記の手順をそのまま踏襲し cap setup chef:deploy して暫くすると...

 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Processing execute[install_td-agent] action nothing (elasticsearch_cookbook::app_install line 39)
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Processing remote_file[/tmp/td-agent_1.1.17-1_amd64.deb] action create (elasticsearch_cookbook::app_install line 44)
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Processing gem_package[fluent-plugin-elasticsearch] action install (elasticsearch_cookbook::app_install line 51)
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Processing gem_package[fluent-plugin-typecast] action install (elasticsearch_cookbook::app_install line 51)
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Processing service[td-agent] action nothing (elasticsearch_cookbook::app_install line 58)
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Processing template[/etc/td-agent/td-agent.conf] action create (elasticsearch_cookbook::app_install line 63)
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Chef Run complete in 6.417893026 seconds
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Running report handlers
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:35+00:00] INFO: Report handlers complete
 ** [out :: xxx.xxx.xxx.5] [2014-01-28T23:41:28+00:00] INFO: Forking chef instance to converge...
    command finished in 8330ms

上記のように見た感じは正常に終了したように見えるが、ちゃんと適用されたかは serverspec を使って確認をする。既に serverspec はインストール済みの環境にて、以下のような spec ファイルを各ホスト毎に用意して上げる。

require 'spec_helper'

describe package('elasticsearch') do
  it { should be_installed }
end

describe package('td-agent') do
  it { should be_installed }
end

describe package('libssl0.9.8') do
  it { should be_installed }
end

describe command('/usr/lib/fluent/ruby/bin/gem list | grep fluent-plugin-elasticsearch') do
  it { should return_exit_status 0 }
end

describe command('/usr/lib/fluent/ruby/bin/gem list | grep fluent-plugin-typecast') do
  it { should return_exit_status 0 }
end

describe service ('td-agent') do
  it { should be_running }
end

describe service ('elasticsearch') do
  it { should be_running }
end

そして、~/.ssh/config を以下のように設定する。

Host xxx.xxx.xxx.*
  User root
  Port 22

最後に rspec spec を実行すると...

..............

Finished in 1.32 seconds
14 examples, 0 failures

上記の通り fail が出ずに終了する。ということは見事に二台のホストに対して cookbook が適用されていると判断出来る。


最後に

  • capistrano を使えば長年*2の悩みだった複数ホストに対して並行して chef を走らせることが出来た
  • 但し、ログの出力がホスト毎ではなくすべてのホストのログが混ざってしまうのと、knife solo に比べて出力が少ないのがちょっと残念
  • やっぱ、ちゃんとやりたければ Chef-Server なのかなと思ってしまう
  • 最後に確認で使った Serverspec は簡単に spec が書けたのは嬉しかった

*1:chef インストール前なので ohai が使えない...

*2:という程でもないけど