酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

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

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

かなり乗り遅れてしまいましたが、最近ようやくRails4.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を使う場合の手順です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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を使う場合の手順です。

1
2
3
4
5
6
# 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を実行。

1
2
3
4
5
6
7
8
9
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を使う場合

1
2
3
4
5
6
7
8
9
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らを生成。

1
bundle exec cap install STAGES=staging,production

Capfileの設定

Capfileを以下のように変更

rbenvを使う場合

1
2
3
4
5
6
7
8
9
10
11
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を使う場合

1
2
3
4
5
6
7
8
9
10
11
12
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を使う場合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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を使う場合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)に記述していきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
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コマンドで設定を確認。
(フォルダの生成等も行ってくれます)

1
2
3
4
5
# stagingのチェック
cap staging deploy:check

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

デプロイ手順

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

1
2
3
4
5
# stagingへのデプロイ
cap staging deploy

# productionへのデプロイ
cap production deploy

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

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

1
2
3
4
5
6
7
8
9
10
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, 'master'の部分を以下のように書き直し。

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

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

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

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

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

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

Special Thanks

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用の設定手順を追記

おすすめの書籍