Capistrano 3系でちょうどマッチした利用方法が見つからなかったので、試行錯誤した結果をまとめた。
Capistranoでのrsyncを利用したRubyアプリケーションのデプロイ
使用するライブラリ
- capistrano(3系)
- bundler
- capistrano-rsync
- capistrano-bundler
デプロイのフローについて
リポジトリがアプリケーションが動作するサーバーのネットワークからアクセスできないという事情があったので、事前に依存ライブラリを取得した上で、リリースできるように、下記のようなデプロイのフローにした。
イメージとしては、JavaでWARとかにパッケージングしたのを配布する感じ。
- デプロイサーバー上で、リポジトリからソースの取得
- デプロイサーバー上で、あらかじめ取得したソースが依存しているライブラリを取得
- 実行サーバーに対して、リソースの展開
- 実行サーバーでのライブラリのインストール
デプロイサーバーへのコピー処理
Capistrano3系では、capistrano-rsyncというgemが、ちょうど上記の動作フローとマッチした実行ステップをもっていたので、このライブラリを使用することにした。
大雑把なステップは下のような感じ。
- リポジトリからソースの取得 (rsync:stage)
- 実行サーバーへのリソースのコピー (rsync:release)
依存ライブラリの取得処理
依存ライブラリの取得に、bundle package --all
を利用する。こうすることで、あらかじめ、vendor/cache
に、依存しているライブラリがダウンロードされる。
実行するステップについては、リポジトリからソースの取得のタイミングで行うことで、実行サーバーへコピーする時にvendor/cache
も含めて、コピーされるようにする。
また、platformに依存して、インストールするgemが変わるようなもの(libv8とか)については、デプロイ作業を行うサーバーのplatformと実行サーバーのplatformが異なると、インストールが失敗するので、事前に、gem fetch
等で取得しておく。
namespace :package do
desc 'packaging gems'
task :gems do
run_locally do
Dir.chdir 'tmp/deploy' do
# bundlerでの環境変数を引き継がない状態で、実行
Bundler.with_clean_env do
system 'BUNDLE_GEMFILE=Gemfile bundle package --all --quiet'
# 環境(platform)に依存しているライブラリがあれば別途、取得
end
end
end
end
end
after 'rsync:stage', 'package:gems'
rsync処理での設定
namespace :rsync do
# 3.2系から、scmのset_current_revisionが呼ばれるようになったことに対応
# cf. https://github.com/moll/capistrano-rsync/issues/15
# internally needed by capistrano's "deploy.rake"
task :set_current_revision do
run_locally do
within fetch(:rsync_stage) do
rev = capture(:git, 'rev-parse', 'HEAD')
set :current_revision, rev
end
end
end
# rsyncのコマンドオプションを指定
task :set_options do
set :rsync_options, %w(-az --delete --delete-excluded --exclude .git*)
end
end
before 'rsync', 'rsync:set_options'
デプロイ処理での設定
rsync
を使う設定と、取得したパッケージを利用するように、bundler
のオプションを追加する。
set :repo_url, '<gitリポジトリのURL>'
# :gitの代わりに、:rsyncを指定
set :scm, :rsync
## Bundler
set :bundle_path, -> { shared_path.join('bundle') }
set :bundle_without, %w(development test).join(' ')
# --localオプションを指定することで、vendor/cache経由でインストール
set :bundle_flags, '--deployment --local'
パッケージングしたライブラリの取り回しの修正
上記の設定だと、毎回のリリースごとに、bundlr
がパッケージングしたvendor/cache
が丸ごとコピーされてしまい、ディスクスペース的に無駄なので、deploy.rb
の:linked_dir
に、vendor/cache
を追加した上で、シンボリックリンクをはるようにします。
# deploy.rbでのシンボリックリンクの対象にvendor/cacheを追加
set :linked_dirs, %w(log tmp/pids tmp/cache tmp/sockets vendor/bundle vendor/cache)
上記で作成したシンボリックリンクのリンク先を書き換えて、rsync
しているディレクトリのvendor/cache
を指すようにします。
namespace :release do
desc 'symlink cache dir'
task :symlink_cache do
on roles(:app) do
within release_path do
execute "cd '#{release_path}'; ln -sfn #{fetch(:deploy_to)}/#{fetch(:shared_path)}#{fetch(:rsync_cache)}/vendor/cache vendor/cache"
end
end
end
end
after 'deploy:symlink:linked_dirs', 'release:symlink_cache'