Capistrano3 で asset_sync をローカル環境で実行してからデプロイする

  • 27
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

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 を利用しています。

Gemfile
gem 'asset_sync'
gem 'dotenv-rails'
config/asset_sync.yml
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
.env
# 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 ファイルを設置しています。

lib/capistrano/tasks/application.cap
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 の有効/無効を切り替えるために設定を追加します。

config/deploy/production.rb
set :asset_sync_enabled, true

asset_sync のタスクを追加します。
asset_sync_enabled が true の場合は、asset_sync を実行し、false の場合は通常通りリモートサーバー上で assets:precompile を実行しています。

lib/capistrano/tasks/asset_sync.cap
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

デプロイ時にタスクが実行されるように設定を追加します。

config/deploy.rb
namespace :deploy do
  before :starting, 'asset_sync:run'
end

Deploy

あとは、

$ bundle exec cap production deploy

を実行するとデプロイ時に asset_sync が実行されます。

参考

今回、参考にさせていただいた記事はこちらです。
Capistrano3でasset_syncしてからデプロイする