[rails]capistrano3でrole指定したサーバが複数台ある場合に、ある1台でのみ実行する方法
capistrano 3.2.1 で確認 capistrano3でrole指定したサーバが複数台ある場合に、ある1台でのみ実行する方法です。
namespace :deploy do
task :primary_task do
# primaryメソッドを使用
on primary :app do
# :app role のprimaryサーバでのみ実行される処理
end
end
end
上記のようにprimaryメソッドを使うことでできました。
db:migrateもこのprimaryメソッドで実行されているようです。
server設定で明示的にprimaryを指定していない場合は、該当roleの1台目のサーバがprimaryになるようです。
検証として、以前このブログで紹介した s3cmdを使ってs3にアップロードするコマンド をcapistrano3経由で実行したいと思ったので試してみました。
事前準備
まずは上記のコマンドをシェルスクリプトにまとめて s3sync.sh を作成
#!/bin/sh
conf="./.s3cfg"
if [ "${1}" = "s3://sample-development" ]; then
conf="./.s3cfg_dev"
fi
s3cmd -c $conf -P --exclude-from .s3ignore --follow-symlinks sync ./public/ $1 $2
開発版(sample-development)の場合は開発版の設定を使用するようにしてみました。
これで
./s3sync.sh s3://sample-development --dry-run
という風に書けば、sample-developmentバケットにpublic以下をdry-run実行できるようになりました。
capistrano3設定
最初、taskに以下のようにroleがappの時にs3アップロードを実行するようにしようと思ったのですが、
namespace :deploy do
task :s3update do
on roles(:app) do
# s3アップロード処理
end
end
end
これだとapp roleのサーバが複数ある場合に、各サーバでs3アップロードが実行されてしまいます。
そこでprimaryメソッドを使用するように変更します。
set :is_update_s3, ask('s3を更新しますか?', 'yes')
namespace :deploy do
task :s3update do
on primary :app do
# rails_envを元にバケット名を指定
set :bucket_name, case fetch(:rails_env)
when :development
'sample-development'
when :staging
'sample-staging'
when :production
'sample-production'
end
# アップロード内容確認
execute "cd #{release_path} && ./s3sync.sh s3://#{fetch(:bucket_name)} --dry-run"
# yesの場合はアップロード
if fetch(:is_update_s3) =~ /yes/i
execute "cd #{release_path} && ./s3sync.sh s3://#{fetch(:bucket_name)}"
end
end
end
before :restart, 'deploy:s3update'
end
こんな感じにすると、cap deploy時にapp roleのサーバ1台のみがs3アップロードコマンドを実行してくれるようになります。