capistranoのマルチステージ拡張機能とcapistrano-unicornを一緒に使う際のTips

要約

capistranoのマルチステージ拡張機能とcapistrano-unicornを一緒に使う時、config/deploy.rbにrequire "capistrano-unicorn"を記述すると、unicorn系のcapタスクがステージ毎に用意した設定の内容を正しく認識してくれません(例えば/u/appsなんとかにアプリがデプロイされたものとしてunicornを起動しようとする)。

require "capistrano-unicorn"を各ステージ用設定ファイルの末尾に書いておくと、正しくステージ毎の設定を反映してくれます。


背景

現バージョンのCapistrano(この記事を書いている時点では2.13.5)には、もともとcapistrano-ext gemとして開発されていたマルチステージ拡張が組み込まれていて、ステージングサーバーにでプロイする時とプロダクションサーバーにデプロイする時で設定を切り替えることができるようになっています。

この機能を使いたい時は、
  1. config/deploy.rbに以下を追記
    require "capistrano/ext/multistage"
    set :stages, ステージ名の文字列配列
    set :default_stage, デフォルトステージ名
  2. config/deployディレクトリにステージ毎の設定ファイルを用意(ファイル名はステージ名.rb)
  3. デプロイ先によらない設定はconfig/deploy.rbに、ステージ毎に切り替えたい設定はconfig/deploy下のそれぞれの設定ファイルに記述
  4. capコマンドを実行する時に、capの後にステージ名を記述する
でOK。

例えば、

config/deploy.rb
...
require "capistrano/ext/multistage"
set :stages, ["staging", "production"]
set :default_stage, "staging"
...
config/deploy/staging.rb
server "1.2.3.4", :app, :web, :db, :primary => true

config/deploy/production.rb
server "5.6.7.8", :app, :web, :db, :primary => true

という設定をすると、cap staging deployで1.2.3.4に、cap production deployで5.6.7.8にデプロイしてくれるようになります。


一方、capistrano-unicornはunicorn関係のタスクを追加してくれるcapistranoプラグインです。capistrano-unicorn gemをインストールし、capistranoの設定ファイル中にrequire "capistrano-unicorn"と書いておけば、unicorn:start、unicorn:stop、unicorn:reloadなどのタスクが追加されます。また、deploy:restartでunicorn:reloadが呼び出されるようになり、デプロイ後にunicornが起動していなければ起動、起動していればunicornのマスタプロセスにUSR2シグナルを送ってリロードしてくれるようになります。


先日マルチステージ拡張機能とcapistrano-unicornを組み合わせて使おうとしたところ、unicorn系のタスクがうまく動かないという問題が発生しました。


問題

ステージングサーバーとプロダクションサーバーでsshユーザーやデプロイ先を変更したかったので、こんな定義をしていました。

config/deploy.rb
...
require "capistrano/ext/multistage"
require "capistrano-unicorn"
set :stages, ["staging", "production"]
set :default_stage, "staging"
...

config/deploy/staging.rb
server "1.2.3.4", :app, :web, :db, :primary => true
set :user, "service"
set :deploy_to, "/home/#{user}/#{application}"
set :rails_env, "staging"

config/deploy/production.rb
server "5.6.7.8", :app, :web, :db, :primary => true
set :user, "support"
set :deploy_to, "/home/#{user}/apps/#{application}"
set :rails_env, "production"

するとunicorn系のタスクを実行した時に、デプロイ先パスがおかしくなってしまいます。例えば、unicorn:reloadでunicornが起動しているかどうか確認する処理の際に、/home/#{user}/#{application}/current/tmp/pids/unicorn.pidがあるかどうかではなく、/u/apps/#{application}/current/tmp/pids/unicorn.pidを見にいきます。

ちなみに /u/apps/#{application}というのはcapistranoのデフォルトのdeploy_to。つまりstaging.rbやproduction.rbのdeploy_toが反映されていないということです。

原因を調べていると、capistrano-unicornのWikiページにこのような記載がありました。
The issue – capistrano loads default configuration and then executes your staging task and overrides previously defined variables.
config/deploy.rbを読み込んだ後、ステージングタスクを実行して改めてステージ毎の設定ファイルが読み込まれ、変数が上書きされるとのこと。

この記述によると、config/deploy.rbのrequire "capistrano-unicorn"でunicorn系のタスクをロードした時点で、タスクが使用するdeploy_toなどの変数の値がfixしてしまい、上書きされた変数を使ってくれないようです。


ワークアラウンド

ステージ毎の設定ファイルが読み込まれる前にunicorn系タスクがロードされてしまうのが問題なら、そもそもrequire "capistrano-unicorn"をconfig/deploy.rbではなくステージ毎の設定ファイルの方に書いて、deploy_toなどを設定した後にロードされるようにしたらいいじゃないか、ということでrequireのタイミングを変更したところ、期待通りにunicorn系タスクが動作するようになりました。

こんな感じでもろもろの変数設定の後にrequireするとうまくいきます。

config/deploy/staging.rb
server "1.2.3.4", :app, :web, :db, :primary => true
set :user, "service"
set :deploy_to, "/home/#{user}/#{application}"
set :rails_env, "staging"
require "capistrano-unicorn"

Comments

Popular posts from this blog

TFS: 別PCでのチェックアウトを取り消す

WPF の RichTextBox に文字列を設定する&取り出す

WPFアプリにアニメーションGIFを表示させる