Capistrano 3系でRails 4.1のデプロイ[rbenv][rvm][ruby2.1]


いまやデプロイツールのデファクトスタンダードとなった『Capistrano3』。stagingやproductionといった複数環境へのデプロイを標準で対応していたり、bundleやmigration、unicornとの連携なども抜群です。

かなり乗り遅れてしまいましたが、最近ようやくRails 4.1をcapistrano3系でデプロイしました。ずっとHerokuやPaaSにばっかり頼っていたのでちょこちょことハマって苦労しました。今後忘れないための忘備録メモっす!

rbenv, rvmの両方に対応しました。オリジナルのcapコマンドの作り方も書きました!


🚜 前提条件

今回の環境では次のような環境を想定しています。

# Webサーバ
(1) unicorn

# Rubyのバージョン管理
(2-A) rbenv
(2-B) rvm

# Cron DSL
(3) whenever

rbenvrvmの両方を使う機会があったので忘備録も兼ねて書いておきます。

🐯 staging/production環境のデータベースの準備

デプロイ先のDBの接続用ユーザーとデータベースを作成するために、次のコマンドをstaging環境とproduction環境で実行します。

MySQLの場合

こちらはMySQLを使う場合の手順です。

mysql -u root -p
# 新規ユーザーを作成する場合
GRANT ALL PRIVILEGES ON database_name.* TO user_name@localhost IDENTIFIED BY 'user_password';
# 既存のユーザーに権限を追加する場合
GRANT ALL PRIVILEGES ON database_name.* TO user_name@localhost;
CREATE DATABASE database_name;
FLUSH PRIVILEGES;
exit
mysql -u user_name -p
SHOW DATABASES;
> +--------------------------+
> | Database |
> +--------------------------+
> | information_schema |
> | database_name | #<= DBの作成成功
> +--------------------------+
exit

PostgreSQLの場合

こちらは、PostgreSQLを使う場合の手順です。

# postgreユーザーになる
sudo su -
su - postgres
# パスワード付きのユーザーを作成する
createuser -s [ユーザー名] -P

🍮 GitHub周りの準備

GitHubで管理しているプライベートなリポジトリを使う場合には、Ubuntu 12.04にデプロイするときにdeploy keyの設定が必要でした。

# サーバ側でやること
1) GitHubのリポジトリにアクセスするための公開鍵・秘密鍵を生成
cd ~
ssh-keygen -t rsa -C test@example.com

# GitHub側でやること
1) 対象のリポジトリのページへ移動
2) Settingsへ移動
3) Deploy keysへ移動
4) Add Deploy Keysで公開鍵を登録

🏀 Gemfileの追加

rbenvを使う場合

Gemfileに次のGemを追加して、bundle installを実行。

gem 'whenever', require: false # cronを使う場合のみ
group :deployment do
gem 'capistrano', '~> 3.2.1'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano-bundler'
gem 'capistrano3-unicorn' # unicornを使っている場合のみ
end

rvmを使う場合

gem 'whenever', require: false # cronを使う場合のみ
group :deployment do
gem 'capistrano', '~> 3.2.1'
gem 'capistrano-rails'
gem 'rvm1-capistrano3', require: false
gem 'capistrano-bundler'
gem 'capistrano3-unicorn' # unicornを使っている場合のみ
end

🍣 Capistranoの設定ファイルを生成

次のコマンドでCapistranoの設定ファイルdeploy.rbらを生成。

bundle exec cap install STAGES=staging,production

🗻 Capfileの設定

Capfileを次のように変更

rbenvを使う場合

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rails'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano3/unicorn' # unicornを使っている場合のみ
require 'whenever/capistrano' # wheneverを使っている場合のみ
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

rvmを使う場合

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rails'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'rvm1/capistrano3'
require 'capistrano/bundler'
require 'capistrano3/unicorn'
require 'whenever/capistrano'
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

🚌 Capistrano共通のデプロイ設定

まず、共通のデプロイ情報をdeploy.rbに記入していきます。

rbenvを使う場合

lock '3.2.1'
set :application, 'APP_NAME'
set :repo_url, 'git@github.com:xxxx.git'
set :deploy_to, '/server/rails/path/to'
set :keep_releases, 5
set :rbenv_type, :system # :system or :user
set :rbenv_ruby, '2.1.2'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all # default value
set :linked_dirs, %w{bin log tmp/backup tmp/pids tmp/cache tmp/sockets vendor/bundle}
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
set :bundle_jobs, 4
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
task :restart do
invoke 'unicorn:restart'
end
end

rvmを使う場合

require 'rvm1/capistrano3'
require 'whenever/capistrano'
lock '3.2.1'
set :application, 'APP_NAME'
set :repo_url, 'git@github.com:xxxx.git'
set :deploy_to, '/server/rails/path/to'
set :keep_releases, 5
set :rvm_type, :system
set :rvm1_ruby_version, '2.1.2'
set :linked_dirs, %w{bin log tmp/backup tmp/pids tmp/cache tmp/sockets vendor/bundle}
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
set :bundle_jobs, 4
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
task :restart do
invoke 'unicorn:restart'
end
end

😸 環境別のデプロイ設定

次に環境ごとに異なる設定をconfig/deploy/staging.rb(production.rb)に記述していきます。

set :branch, 'master'
role :app, %w{USER_NAME@IP_ADDRESS}
role :web, %w{USER_NAME@IP_ADDRESS}
role :db, %w{USER_NAME@IP_ADDRESS}
server 'IP_ADDRESS', user: 'USER_NAME', roles: %w{web app db}
set :ssh_options, {
keys: [File.expand_path('/key/path/to/')],
forward_agent: true,
auth_methods: %w(publickey)
}

🐹 wheneverの設定

サーバ側のcronの設定をコードで簡単に管理できるwheneverは、『Wheneverは導入が超簡単なcrontab管理ライブラリGemです![Rails4.1]』を参考に設定!

🎂 Bitbucket/GitHub(Gitリポジトリ)の設定

ここはBitbucket/GitHubなどでプライベートなGitリポジトリを使っている場合について書きます。

プライベートなリポジトリを使う方法はいくつかありますが、そのうちのひとつの方法として、デプロイ先
のサーバにid_rsa / id_rsa.pubを作成して、公開鍵側をBitbucket/GitHubに
登録する方法があります。

この方法を使う場合のSSH鍵の作成、登録は、拙著
SSH認証キーをBitbucket/GitHubに設定しよう!
に詳しく書いています!

🎃 デプロイ前のチェックリスト・準備

* deploy.rb, staging.rb, production.rbのパラメータをすべて設定したかチェック
* ステージングDB、本番DBの設定をdatabase.ymlに追加しているか?
* デプロイ用Gitリポジトリのブランチが最新の状態か?

上のチェックが完了したら、capコマンドで設定を確認。

(フォルダの生成等も行ってくれます)

# stagingのチェック
cap staging deploy:check
# productionのチェック
cap production deploy:check

🐮 デプロイ手順

デプロイに必要なディレクトリを生成して、デプロイを実行。

# stagingへのデプロイ
cap staging deploy
# productionへのデプロイ
cap production deploy

😼 オリジナルのcapコマンドの作り方

Capistranoを使うとサーバに入ってちょっとしたコマンドを実行するといったこともcapコマンド化できます。

namespace :sample do
desc 'do some rake task'
task :do_some_rake_task do
rvm_prefix = "#{fetch(:rvm1_auto_script_path)}/rvm-auto.sh #{fetch(:rvm1_ruby_version)}"
on roles(:all) do |h|
execute "cd #{current_path} && #{rvm_prefix} bundle exec rake RAILS_ENV=production do_some_rake_task"
end
end
end
end

👽 Apache/nginxの設定

Apacheのバーチャルホストの設定ファイル(sudo vim /etc/http/conf.d/vhost.confなど)をApache VirtualHostの設定を参考に編集。

🐝 deploy時にブランチを選択したい場合

set :branck, 'マスタ'の部分を次のように書き直し。

ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call

🗽 unicorn restartがうまくいかない場合

僕は最近100発100中でこれにハマります。あまりに僕が学習能力なくって泣きそうorz…

UnicornにUSR2シグナル送っても無視される(Bundler::GemfileNotFound)

before_fork do |server, worker|
ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile', ENV['RAILS_ROOT'])
end

unicornでBUNDLE_GEMFILEの場所はちゃんと設定したほうがいいっす!

🚕 参考リンク

capistrano 3.x系を使ってrailsをデプロイ | iii ThreeTreesLight

Capistrano3で快適デプロイ生活!! - Less is Best

🐰 変更来歴

(2014-04-25 23:00) 新規作成

(2014-07-08 20:40) rvm対応

(2014-07-10 20:00) wheneverの記述を追記

(2014-11-02 11:55) GitHub/Bitbucket周りの設定

(2014-11-22 10:05) オリジナルのcapコマンドの作り方を追加

(2014-12-16 22:10) bundle installのjobsオプションを追加

(2015-01-18 12:20) posgreSQL用の設定手順を追記

📚 おすすめの書籍