Capistrano事始め
インストールするまで
サーバを沢山管理することになりました.それらのサーバではrubyを使っていたので,rubyベースのdeployツールCapistranoを使ってみる事にしました.Capistranoは2009/2に作者がもうメンテナンスしないぜと宣言したプロダクトです.とはいっても,コミュニティがメンテすることになるだろうから今後も問題ないだろうなと思ってます.それはそれとして,CapistranoをインストールするにはRubyGemsが必要なのでまずはそこからインストールします.RubyGems の使い方 - WebOS Goodiesを見ながらwgetでファイルをダウンロードして,
# ruby setup.rb
でインストールします.Capistranoは
$ sudo gem install capistrano
でインストールできます.
秘密鍵の管理
普段色々鍵を使っていてdefaultの".ssh/id_dsa"とかを使うようにはしたくなかったので,明示的に鍵を指定するようにしました.もしかしたら,.ssh/configが使えたのかもしれないですが,調べてないです…
role :test1, "sv100.foo.co.jp" task :hostname, :roles => :test1 do run "hostname" end ssh_options[:keys] = %w(/home/daiba/.ssh/capistrano) ssh_options[:auth_methods] = %w(publickey)
これで,test1というロールで指定したホスト群に対して,/home/daiba/.ssh/capistranoという秘密鍵でsshして,hostnameを実行し,その結果を表示します.
メニュー化
Capistranoはdefaultでcapfileという名前のファイルを選んで,その上で定義したルールを実行しますが,-fオプションを付けるとファイルを指定することもできます.
$ cap hostname
$ cap -f CAPFILE hostname
ロールを沢山作った時にロールが覚えられなくなるだろうと思ったので,menuというロールを作って,そこから選択できるようにしてみました.
role :test1, "sv100.foo.co.jp" desc "menu list" task :menu do Capistrano::CLI.ui.say("\nThis is with a oneline menu layout...") Capistrano::CLI.ui.choose do |menu| menu.layout = :one_line menu.header = "Execute" menu.prompt = "Application? " menu.choice :hostname do hostname end menu.choice :whoami do whoami end menu.choices(:skip, :exit) do Capistrano::CLI.ui.say("Choose not to run..") end end end task :hostname, :roles => :test1 do run "hostname" end task :whoami, :roles => :test1 do run "whoami" end
この場合だと,hostnameとwhoamiが選択できます.
sudoでパスワードを入力
sshするだけではなく,別ユーザになってコマンドを実行したいときがあります.この場合はsudoを利用するわけですが,そのときはこんな感じに使います.
role :test1, "sv100.foo.co.jp" set :sudo_password, 'Password:' task :whoami do run "#{sudo :as => 'oops'} whoami", roles => :test1 do |channel, stream, data| if stream == :out puts channel[:host] + ': ' + data end end end
"set :sudo_pasword, 'Password:'"はsudoプログラムが出力する文字列を指定しているので,システムによっては変更する必要があるでしょう.defaultでは"sudo password: "が割り当てられています.これで,sudoになる時のパスワードがキャッシュされていなければCapistranoが質問してきます.sudo変数を使うのでなければ,以下のような使い方もできます.
role :test1, "sv100.foo.co.jp" set(:my_password) { Capistrano::CLI.password_prompt("My password: ") } task :whoami do run "sudo -u ops whoami", :roles => :test1 do |channel, stream, data| if data =~ /^Password:/ channel.send_data "#{my_password}\n" end if stream == :out puts data end end end
dynamicにロールのターゲットを作成
role対象のホストを一個づつ書くのは面倒なので,スクリプトをそこに書きたくなります.ターゲットは"hostA, hostB, hostC"のような文字列か,配列を与えることができるので,こんな使い方ができます.
role(:servers) do hosts = Array.new 100.upto 200 do |x| hosts.push('sv' + String(x) + '.foo.co.jp') end hosts end task :hostname, :roles => :servers, :max_hosts => 10 do run "hostname" end
[5/20追加]1000台のマシンに対して実行したらプロセスがうんともすんとも言わなかったので調べてみたら,defaultではsshセッションの上限が設定されてないようでした.そのため,大量のホストにコマンドを実行する際には,":max_hosts"で一度に張るセッションの上限を設定する必要があります.":max_hosts"は将来なくなるかもしれないオプションのようです.
scpでファイル配布(書くのを忘れてたので追加)
ファイル配布にはsftpとscpが使えます.普段scpを使ってるのでそっちしか試してません.設定は以下のようになるのですが,
role :test1, "sv100.foo.co.jp" desc "upload file" task :upload!, :roles => :test1 do upload("target_file.txt", "/tmp", :via => :scp) end
uploadはローカルマシンからターゲットマシンへの転送,逆方向の場合はdownloadになります.
さて
苦労した割にはtipsが溜まらなかったです.ここでやっているようなことをArcher - yet another deployment tool - metacpan.orgでやり直すかどうかを悩んでいるところ.