LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログです。

capistrano-bundle_rsyncを利用したデプロイ方式に変更しました

Webエンジニアの森脇です。LCLでは、Capitranoを利用してRailsアプリケーションのデプロイを行っていましたが、「capistrano-bundle_rsync」を利用する方式に変更しましたので、背景含めて紹介いたします。

デプロイの概要

capistranoを利用したデプロイでは、デプロイサーバではcapistranoを実行し、各Webサーバへsshでログインし、各種デプロイ関連処理を行います。

f:id:lcl-engineer:20180927143424p:plain

このデプロイ方式では、以下の問題がありました。

  • デプロイ中は各Webサーバのリソースを多く消費してしまうため、アクセスが多いときはデプロイができない
  • デプロイ時間が、Webサーバのスペックへ依存してしまう。

そこで、デプロイサーバでbundle install,precompileを行い、各Webサーバにrsyncで配布する方式に変更しました。

f:id:lcl-engineer:20180927144253p:plain

実現方法

capistranoを拡張した、capistrano-bundle_rsyncというgemを利用させていただいます。

GitHub - sonots/capistrano-bundle_rsync: Deploy an application and bundled gems via rsync

使い方は、Readmeに書いているので紹介するまでもないのですが、既にCapistranoを利用している場合の移行手順について紹介します。

Gemfileにgem追加して、bundle installをします。

gem 'capistrano-bundle_rsync'

Capfileに以下を追加します。(capistrano-3.7以上を使う場合は、記載方法が異なります)

require 'capistrano/bundle_rsync'

deploy.rb等に以下を追加します。

set :scm, :bundle_rsync 

最低限必要な設定はこれだけで、capistrano-bundle_rsyncを利用した方式に切り替わります。あとは、必要に応じて各種パラメータを設定しています。

clone先の指定

capistrano-bundle_rsync を使うと、デプロイサーバ上でgit cloneを行います。LCLでは、一つのデプロイサーバで複数種類のアプリケーションにデプロイするため、アプリケーションごとに、clone先を変更しています。

例)
set :bundle_rsync_local_base_path, "#{Dir::pwd}/.local_repo/aaa-production"
set :bundle_rsync_local_base_path, "#{Dir::pwd}/.local_repo/bbb-production"

precompile用のTaskの作成

precompileは、デフォルトではWebサーバ側で行われます。precompileをデプロイサーバで行うために、以下のTaskを作成しました。( Readmeにも記載がありますが、rsync部分を少し変更しています)

task :precompile do
  config = Capistrano::BundleRsync::Config
  run_locally do
    Bundler.with_clean_env do
      within config.local_release_path do
        execute :bundle, 'install' # install development gems
        execute :bundle, 'exec rake assets:precompile'
      end
    end
    
    hosts = release_roles(:all)
    rsync_options = config.rsync_options
    Parallel.each(hosts, in_threads: config.max_parallels(hosts)) do |host|
      ssh = config.build_ssh_command(host)
      execute :rsync, "#{rsync_options} --rsh='#{ssh}' #{config.local_release_path}/public/ #{host}:#{shared_path}/public/"
    end
  end
end
before "bundle_rsync:rsync_release", "precompile"

Webサーバ側ではprecomileが走らないように、Capfileから以下の記述を削除しています。

# require 'capistrano/rails/assets'

まとめ

デプロイ方式の変更により、当初問題であった点は解決できました。デプロイ周りはまだまだ課題がありますが、インフラ周りを改善できるエンジニアが不足しています。Railsでの開発もしたいし、AWS関連のデプロイ周りの最適化等もしたい、という方はぜひご連絡ください!