Rails アプリを Capistrano でデプロイするとき deploy:assets:precompile
タスクでフロントまわりのビルドが走ります。
デプロイ先のサーバーが低スペックだと、そのビルドに時間がかかってデプロイがなかなか終わりません。その上、サーバーの負荷も上昇し、サービスも不安定になってしまいます。
そこでプリコンパイルだけローカルで行うようにする例がこちらです。
config/deploy.rb
unless ENV["REMOTE_BUILD"] == "1"
# 元のタスクの内容は消しておく(重要)
Rake::Task["deploy:assets:precompile"].clear
# 新しく定義
# cap production deploy:assets:precompile
desc "ローカルで assets:precompile してコピー"
task "deploy:assets:precompile" do
tmpdir = "/tmp/__repository_#{fetch(:application)}_#{fetch(:stage)}"
run_locally do
execute :rm, "-fr #{tmpdir}"
execute "git clone #{fetch(:repo_url)} --depth 1 --branch #{fetch(:branch)} #{tmpdir}"
within tmpdir do
# database.yml はなくてもいいはずだけど assets:precompile を実行するタイミングで
# initializers/* のなかでDBアクセスしてしまったりすることもあるので
# database.yml がない場合は必要に応じて用意する
# この例ではプリコンパイル時専用の database.precompile.yml を config/database.yml としています
execute :cp, "-v", "#{__dir__}/database.precompile.yml", "config/database.yml"
# master.key も必要に応じてコピーする
execute :cp, "-v", "#{__dir__}/master.key", "config"
# もし NODE_ENV=production な環境でビルドするときは
# devDependencies が対象にならないので --production=false の引数をつけとくといい
execute :yarn
# 環境変数 STAGE, NODE_ENV, RAILS_ENV を有効にしておく
with stage: fetch(:stage), rails_env: fetch(:rails_env), node_env: fetch(:rails_env) do
# sh -c で実行しているのは rbenv 関連プレフィクスをつけたくないため。
# execute :bundle で実行したりすると rbenv_map_bins のフックが影響して
# リモートで execute する用の rbenv がついてしまう
execute :sh, "-c 'bundle exec rails -t assets:precompile'"
end
end
# public/{assets,packs} をデプロイ先に転送
within "#{tmpdir}/public" do
roles(:web).each do |e|
execute :rsync, "-au --delete -e ssh assets packs #{e.user}@#{e.hostname}:#{release_path}/public"
end
end
execute :rm, "-fr #{tmpdir}"
end
end
end
config/deploy.rb
に追加、または lib/capistrano/tasks/local_build.rake
などに保存します。
あとは普通に cap production deploy
するだけです。
これで私の環境では23分26秒かかっていたデプロイが4分3秒になりました。
なお、上のタスクはごちゃごちゃしていますが、やっていることは簡単でリモートでプリコンパイルするタイミングで次の処理を行います。
- ローカルに git clone
- yarn && rails assets:precompile
- pubilc/{assets,packs} をサーバー側にコピー
注意する点はこちらです。
- database.yml が git の管理下にある場合は別ファイルからコピーする必要はない
- ssh 経由で rsync が使えること
プリコンパイルの影響でデプロイが大変という方がいましたら試してみてください。