LoginSignup
9
9

More than 5 years have passed since last update.

Railsのプリコンパイルをローカル環境で行ってデプロイを高速化する方法

Last updated at Posted at 2018-08-19

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秒になりました。

なお、上のタスクはごちゃごちゃしていますが、やっていることは簡単でリモートでプリコンパイルするタイミングで次の処理を行います。

  1. ローカルに git clone
  2. yarn && rails assets:precompile
  3. pubilc/{assets,packs} をサーバー側にコピー

注意する点はこちらです。

  • database.yml が git の管理下にある場合は別ファイルからコピーする必要はない
  • ssh 経由で rsync が使えること

プリコンパイルの影響でデプロイが大変という方がいましたら試してみてください。

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9