rake assets:precompile
で出力されるファイルを Amazon S3 などでホスティングしたい場合、asset_sync という gem が便利そうなので使ってみました。
asset_sync はrake assets:precompile
実行時に Amazon S3 に出力ファイルをアップロードしてくれる優れものですが、デプロイ先のサーバーが複数台ある場合、複数台でそれぞれrake assets:precompile
を実行してしまうのは冗長ですし、on primary(:web)
とかすると manifest ファイル配るのはどうしよう。git に push するのもログが汚れてイヤだなーっと、これまた悩みそうです。
そこで、今回はデプロイ時にローカル環境でrake assets:precompile
をしてから、manifest ファイルをデプロイ先サーバーに配る方式をとってみました。
今回の環境
- capistrano と railsアプリケーション は別々のリポジトリで管理
- asset_sync の設定は dotenv-rails で管理
- デプロイ先のサーバーは複数台
- 環境ごとに asset_sync したり、通常通り assets:precompile できるようにしたい
各種設定
Rails アプリケーション
asset_sync と、その設定内容の管理に dotenv-rails を利用しています。
gem 'asset_sync'
gem 'dotenv-rails'
defaults: &defaults
enabled: <%= ENV['ASSET_SYNC_ENABLED'] %>
fog_provider: <%= ENV['ASSET_SYNC_PROVIDER'] %>
fog_directory: <%= ENV['ASSET_SYNC_FOG_DIRECTORY'] %>
fog_region: <%= ENV['ASSET_SYNC_FOG_REGION'] %>
fog_endpoint: <%= ENV['ASSET_SYNC_FOG_ENDPOINT'] %>
aws_access_key_id: <%= ENV['ASSET_SYNC_AWS_ACCESS_KEY_ID'] %>
aws_secret_access_key: <%= ENV['ASSET_SYNC_AWS_SECRET_ACCESS_KEY'] %>
existing_remote_files: 'keep'
manifest: true
gzip_compression: true
development:
<<: *defaults
staging:
<<: *defaults
production:
<<: *defaults
# asset_sync
ASSET_SYNC_ENABLED=false
ASSET_SYNC_PROVIDER=''
ASSET_SYNC_FOG_DIRECTORY=''
ASSET_SYNC_FOG_REGION=''
ASSET_SYNC_FOG_ENDPOINT=''
ASSET_SYNC_AWS_ACCESS_KEY_ID=''
ASSET_SYNC_AWS_SECRET_ACCESS_KEY=''
Capistrano
今回、capistrano と Rails アプリケーション は別々のリポジトリで管理していたため、ローカル環境に Rails アプリケーションをセットアップするタスクを追加します。
最新ソースを git から取得し、bundle install
、環境変数を管理する .env ファイルを設置しています。
namespace :application do
desc 'Setup local application'
task :setup do
run_locally do
# application のソースを取得
if test "[ ! -d #{fetch(:application)} ]"
execute :git, :clone, fetch(:repo_url), fetch(:application)
end
Dir.chdir(fetch(:application)) do
# 最新ソースを取得
execute :git, :checkout, fetch(:branch)
execute :git, :fetch, "origin"
execute :git, :reset, "--hard origin/#{fetch(:branch)}"
# bundle install
Bundler.with_clean_env do
execute "bundle install --path ./vendor/bundle"
end
# .env を設置
execute :rm, "-rf .env"
execute :ln, "-s ../config/deploy/env/env.#{fetch(:rails_env)} .env"
end
end
end
end
環境ごとに asset_sync の有効/無効を切り替えるために設定を追加します。
set :asset_sync_enabled, true
asset_sync のタスクを追加します。
asset_sync_enabled が true の場合は、asset_sync を実行し、false の場合は通常通りリモートサーバー上で assets:precompile を実行しています。
namespace :deploy do
namespace :asset_sync do
desc 'Run asset_sync'
task :run do
if fetch(:asset_sync_enabled)
invoke 'application:setup'
invoke 'deploy:asset_sync:precompile'
invoke 'deploy:asset_sync:upload_manifest'
invoke 'deploy:asset_sync:cleanup'
Rake::Task['deploy:compile_assets'].clear_actions
end
end
desc 'Run assets:precompile'
task :precompile do
run_locally do
Dir.chdir(fetch(:application)) do
Bundler.with_clean_env do
execute "bundle exec rake assets:precompile RAILS_ENV=#{fetch(:rails_env)} ASSET_SYNC_ENABLED=#{fetch(:asset_sync_enabled)}"
end
end
end
end
desc 'Upload manifest'
task :upload_manifest do
Dir.chdir(fetch(:application)) do
on roles(fetch(:assets_roles)) do
if test "[ ! -d #{release_path}/public/assets ]"
execute "mkdir -p #{release_path}/public/assets"
end
file_path = Dir::glob('public/assets/manifest*').first
upload!(file_path, "#{release_path}/public/assets/")
end
end
end
desc 'Cleanup assets'
task :cleanup do
run_locally do
Dir.chdir(fetch(:application)) do
Bundler.with_clean_env do
execute "bundle exec rake assets:clobber"
end
end
end
end
end
end
デプロイ時にタスクが実行されるように設定を追加します。
namespace :deploy do
before :starting, 'asset_sync:run'
end
Deploy
あとは、
$ bundle exec cap production deploy
を実行するとデプロイ時に asset_sync が実行されます。
参考
今回、参考にさせていただいた記事はこちらです。
Capistrano3でasset_syncしてからデプロイする