ruby製デプロイツール capistranoについて調べてみた
参考
capistrano は、以前関わっていたプロジェクトでも利用していたけど、 コマンド打ったり、タスクの微調整をする程度だったので、詳しいことは 全く知らなかった。 今回、新しいプロジェクトでcapistranoでデプロイを行なう機会に、 中身を調べてみた。
cap
cap コマンドは、rubyスクリプトだった。
$ file /usr/bin/cap /usr/bin/cap: a /usr/bin/ruby1.8 script text executable |
#! /usr/bin/ruby1.8 require 'capistrano/cli' Capistrano::CLI.execute |
Capistrano::CLI.execute を実行してる
引数の解析
- -r Preserve task roles
- -S pre_vars の指定
- -s varsの指定
- -T tasksの指定
- -X skip system config
- -x skip user config
- ※他にもある。
引数の解析の後、capistrano/cli/execute.rb で主な処理がexecute!で行なわれてる
# Using the options build when the command-line was parsed, instantiate # a new Capistrano configuration, initialize it, and execute the # requested actions. # # Returns the Configuration instance used, if successful. def execute! config = instantiate_configuration(options) config.debug = options[:debug] config.dry_run = options[:dry_run] config.preserve_roles = options[:preserve_roles] config.logger.level = options[:verbose] set_pre_vars(config) load_recipes(config) config.trigger(:load) execute_requested_actions(config) config.trigger(:exit) config rescue Exception => error handle_error(error) end |
- set_pre_vars で、pre_varsを設定し、
- load_recipes で、標準レシピ、システム設定/レシピ、ユーザ設定/レシピ、Capfile と引数で指定したレシピをloadする。
- config.load “standard” で読み込まれるのは、capistrano/recipes/standard.rb。taskは、invokeとshell
- config.load(options[:sysconf]) では、/etc/capistrano.conf があれば、読み込まれる。gemsでインストールしたけどデフォルトでは存在しなかった。
- config.load(options[:dotfile]) では、~/.caprc があれば読み込まれる。
- Array(options[:recipes]).each { |recipe| config.load(recipe) }で、Capfile と -f で指定したファイルが読み込まれる。
- config.trigger(:load)で前処理に登録されている処理を実行し、
- execute_requested_actions(config)で主な処理を実行し、
- config.trigger(:exit)で後処理を実行する。
execute_requested_actionsでは、 varsを設定し、options[:actoins]の処理を、それぞれ実行する。
def execute_requested_actions(config) Array(options[:vars]).each { |name, value| config.set(name, value) } Array(options[:actions]).each do |action| config.find_and_execute_task(action, :before => :start, :after => :finish) end end |
find_and_execute_task でのタスク実行処理を見てみる。
# Attempts to locate the task at the given fully-qualified path, and # execute it. If no such task exists, a Capistrano::NoSuchTaskError will # be raised. def find_and_execute_task(path, hooks={}) task = find_task(path) or raise NoSuchTaskError, "the task `#{path}' does not exist" trigger(hooks[:before], task) if hooks[:before] result = execute_task(task) trigger(hooks[:after], task) if hooks[:after] result end |
- 個々のタスクの前処理があれば実行する
- タスク実行
- 個々のタスクの後処理があれば実行する
デフォルトのCapfileで、load “deploy” してるので、capistrano/recipes/deploy.rb が読み込まれるらしい。 deploy.rb には、namespace :deploy の中で、複数のtaskが定義されていた。
ここまで読んだところで理解したこと
- レシピとは、タスクをグループ化したもの
- タスクは、レシピやコンフィグファイル内のtaskメソッドで定義する。
- 複数のタスクをnamespaceで纏めることができる。(deploy:migrateなどと指定することになる)
- タスクの中で他のタスクを実行したりする。Makefileのターゲットみたいなことができる。
ふむふむ。主な流れはシンプルらしい。しかし、CLIというクラスがでかい。
要は、config.find_and_execute_task でそれぞれのタスクを実行するので、 どんなタスクがあるのかってのを調べればいいのかな。
追記
capistrano/recipes/deploy.rb にrails用の基本デプロイタスクが用意されているので、必要なタスクだけを、Capfileとか、そこから読込まれるコンフィグファイルで上書きしてあげればいいということらしい。
追記2
コマンドの実行対象になるサーバは、run メソッドが呼ばれた後に、current_taskを参照して、taskに設定されているrolesをチェックして実行対象のサーバを選んでるらしい。その方がフレキシブルなのかな。task定義時に対象サーバが決定しちゃう方が堅そうだけど。