Capistranoでタスクの実行対象サーバを絞り込む方法

Railsアプリのデプロイツールとしてデファクトスタンダード的な位置にあるCapistranoについて。

TL;DR

HOSTSとROLESではなく、HOSTFILTERとHOSTROLEFILTERを使え。

タスクの実行先制限方法

Capistranoは、デプロイ先サーバに"ロール"を設定し、特定のロールに所属するサーバ全てに対して一括でなにかしらの処理を実行させることができる。

# deploy.rb
server 'webserver1' :web
server 'webserver2' :web
server 'dbserver', :db, :primary => true

...

task :do_something, :roles => :web do
  ...
end
cap do_something
  #=> webserver1, webserver2に対してのみdo_somethingタスクを実行する

なにこれ便利!

しかし、時には特定のサーバに対してのみタスクを実行したい場合もある。例えば、新しいサーバを追加したときはそのサーバに対してだけデプロイしたいだろう。

この場合、やり方は4つある。

HOSTS=server1,server2 cap do_something
ROLES=web,app cap do_something
HOSTFILTER=server1,server2 cap do_something
HOSTROLEFILTER=web,app cap do_something

どれも指定したサーバないし指定したロールに所属するサーバに対してのみタスクを実行させる。

日本語圏の技術ブログで紹介されているのは大抵HOSTSとROLESであるが、個人的にはこれらはお勧めできない。なぜなら、タスクに定義しているロール制限を完全に上書きしてしまうからである。つまり、次のようなことができる。

task :maint, :roles => :web do
  # Webサーバをメンテモードにする処理
end
ROLES=db cap maint
  # => DBサーバに対してmaintを実行できてしまう!

タスクのロール制限は必要があって定義してあるのだから、おいそれと無視して良いはずが無い。

一方、HOSTFILTERとHOSTROLEFILTERはタスクのロール制限でサーバを絞り込んだ結果に対して、追加で絞り込みをかける、という動作をする。そのため、より安全である。

HOSTROLEFILTER=web cap do_something
  # => webserver1にのみdo_somethingする

HOSTROLEFILTER=db cap do_something
  # => なにもしない。タスク側の設定でWebサーバに制限されるため、そこからDBサーバを選ぶことはできない

コンソールへの入力ミスで意図しないサーバに対してタスクを実行してしまう危険性が軽減されるので、HOSTFILTERとHOSTROLEFILTERを使ったほうが安全である。