酒と泪とRubyとRailsと

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

Capistrano2系 複数環境へのデプロイ[localhostへのデプロイ][Rails]

Eye Catch Image

Capistranoはデプロイプロセスを自動化してくれるGemです。今回はCapistranoを使ってローカルのステージング環境とサーバの本番環境にデプロイする手順を書きます。

もし、ProductionサーバへのデプロイとBitbucketのGitリポジトリを使う場合は、2012年12月に書いたRals3.2.9で始める Git連携Capistranoによる自動デプロイがオススメっす。


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

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

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

ローカルへのSSH接続を許可する

localhostへのSSH接続について設定する。Macを使っている場合は、システム環境設定 => 共有 => リモートログインを有効にします。

Mac リモートログインを有効に

Gemfileの追加

Gemfileを追加して、bundle installを実行。

1
2
3
4
5
6
7
8
9
10
group :deployment do
  # Capistraono (Deploy支援)
  gem 'capistrano'
  gem 'capistrano-ext'
  gem 'capistrano_colors'
  gem 'rvm-capistrano'
end

# メンテナンスモード画面の表示
gem 'turnout'

Capistranoの設定ファイルを生成

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

1
2
3
4
capify .
> [add] writing './Capfile'
> [add] writing './config/deploy.rb'
> [done] capified!

続いて、staging環境/production環境専用のCapistrano設定ファイルを作成。

1
2
3
mkdir config/deploy
touch config/deploy/staging.rb
touch config/deploy/production.rb

config/deploy/staging.rbにはstaging環境固有の設定を次項で記述。
config/deploy/production.rbにはproduction環境固有の設定を次項で記述。

Capistrano 共通のデプロイ設定

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

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# -*- coding: utf-8 -*-
set :default_stage, "production"

# 複数環境にデプロイできるようにする
require "capistrano/ext/multistage"

# capistranoの出力をカラーに
require 'capistrano_colors'

# cap deploy時に自動で bundle installを実行
require "bundler/capistrano"

# RVM
require "rvm/capistrano"
#### RVMで利用するRubyのバージョンを設定(1.9.3を変更) ####
set :rvm_ruby_string, '1.9.3'
set :rvm_type, :user

# gitリポジトリの設定
#### gitリポジトリをセット ####
set :repository,  "file:///app/path/to/.git"
set :scm, :git
set :branch, "master"
set :deploy_via, :remote_cache

# SSH
set :use_sudo, true
set :default_run_options, :pty => true
ssh_options[:forward_agent] = true

set :normalize_asset_timestamps, false
# 過去のデプロイしたフォルダを履歴として保持する数
set :keep_releases, 5

# assets:precompile
namespace :assets do
  task :precompile, :roles => :web do
    run "cd #{current_path} && RAILS_ENV=#{rails_env} bundle exec rake assets:precompile"
  end
end

# メンテナンスモード
namespace :maintenance do
  desc "Maintenance start"
  task :on, :roles => :web do
    on_rollback { run "rm #{current_path}/tmp/maintenance.yml" }
    page = File.read("config/maintenance.yml")
    put page, "#{current_path}/tmp/maintenance.yml", :mode => 0644
  end

  desc "Maintenance stop"
  task :off, :roles => :web do
    run "rm #{release_path}/tmp/maintenance.yml"
  end
end

namespace :deploy do
  # Passengerの実行ユーザー/Groupをセット
  task :set_file_process_owner do
    sudo "chown -R #{user}:#{user_group} #{deploy_to}"
  end

  #### sitemap_generatorを使ってない場合は削除 ####
  desc "sitemapの更新"
  task :refresh_sitemaps do
    run "cd #{latest_release} && RAILS_ENV=#{rails_env} bundle exec rake sitemap:refresh"
  end

  # 本番サーバでPassenger以外を使っている場合は適宜変更して下さい。
  desc "Passenger用に起動/停止タスクを変更"
  task :restart, :roles => :web do
    run "touch #{current_path}/tmp/restart.txt"
  end

  # page_cacheを使用していない場合は不要
  desc "キャッシュhtmlの削除(deploy中に不完全なhtmlを生成しないための対策)"
  task :remove_caches, :roles => :web do
    run "rm -rf #{current_path}/public/index.html"
  end

  #### Wheneverを使っていない場合は削除
  desc "wheneverのアップデート"
  task :whenever_update do
    run "cd #{latest_release} && RAILS_ENV=#{rails_env} bundle exec whenever --update-crontab #{application} -f config/schedule_#{rails_env}.rb"
  end
end
before :deploy, "deploy:set_file_process_owner"

Capistrano Staging環境のデプロイ設定

次に、config/deploy/staging.rbにステージング環境の設定を記述します。(ステージング環境はローカル)

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# -*- coding: utf-8 -*-
#### TEST_APP_STAGINGにアプリ名を登録 ####
set :application, "TEST_APP_STAGING"

# RVM
#### rvmのパス 環境に合わせて変更 ####
set :rvm_path, '~/.rvm'
set :rvm_bin_path, "#{rvm_path}/bin"
set :rvm_lib_path, "#{rvm_path}/lib"

# デプロイ先のフォルダ設定
#### デプロイ先のフォルダを設定 ####
set :deploy_to, "/app/path/to/staging/"
#### デプロイする環境名をセット ####
set :rails_env, "staging"

# デプロイ先のサーバの設定
server "localhost", :app, :web, :db, :primary => true

# Bundle
set :bundle_flags, ""

# SSHユーザの設定
#### USER_NAME, USER_GROUP, PASSWORD, KEYのパス, パスフレーズ、SSHのポート
set :user, "USER_NAME"
set :user_group, "USER_GROUP"
set :password, "PASSWORD"
ssh_options[:keys] = %w(~/.ssh/id_rsa)
ssh_options[:passphrase] = "パスフレーズ"
ssh_options[:port] = "SSHのポート番号"

namespace :deploy do
  #### Powを使っていない場合は削除(環境に合わせて適宜変更)
  desc "Powの環境変数をセット"
  task :set_powenv_and_symlink do
    run "cd #{latest_release} && echo 'export RAILS_ENV=#{rails_env}' > .powenv"
    run "rm -rf /Users/#{user}/.pow/#{application} && ln -s #{latest_release} ~/.pow/#{application}"
  end
end

# deploy ==========================
after :deploy, "deploy:migrate"
after :deploy, "deploy:set_powenv_and_symlink"
after :deploy, "deploy:whenever_update"
after :deploy, "deploy:cleanup" # 古い履歴のフォルダを削除

Capistrano Production環境のデプロイ設定

次に、config/deploy/production.rbに本番環境の設定を記述します。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# -*- coding: utf-8 -*-
#### TEST_APP_PRODUCTIONにアプリ名を登録 ####
set :application, "TEST_APP_PRODUCTION"

# RVM
#### rvmのパス 環境に合わせて変更 ####
set :rvm_path, '/usr/local/rvm'
set :rvm_bin_path, "#{rvm_path}/bin"
set :rvm_lib_path, "#{rvm_path}/lib"

#### デプロイ先のフォルダを設定 ####
set :deploy_to, "/app/path/to/prodcution/"
set :rails_env, "production"

# デプロイ先のサーバの設定
#### デプロイ先のサーバをセット ####
server "SERVER_IP:PORT", :app, :web, :db, :primary => true

# bundle install条件
set :bundle_flags, "--no-deployment --without test development"

# SSH
#### USER_NAME, USER_GROUP, PASSWORD, KEYのパス, パスフレーズ、SSHのポート
set :user, "USER_NAME"
set :user_group, "USER_GROUP"
set :password, "PASSWORD"
ssh_options[:keys] = %w(~/.ssh/id_rsa)
ssh_options[:passphrase] = "パスフレーズ"
ssh_options[:port] = "SSHのポート番号"

# deploy ==========================
after :deploy, "maintenance:on"
after :deploy, "assets:precompile"
after :deploy, "deploy:migrate"
after :deploy, "deploy:restart"
after :deploy, "deploy:remove_caches"
after :deploy, "maintenance:off"
after :deploy, "deploy:refresh_sitemaps"
after :deploy, "deploy:whenever_update"
after :deploy, "deploy:cleanup"

メンテナンス画面の設定

メンテナンス画面での表示のために、config/maintenance.ymlを追加。 (詳細は、tmedetbekov/turnout · GitHubを参照)

1
2
3
4
5
6
7
8
---
reason: Someone told me I should type <code>sudo rm -rf /</code>
allowed_paths:
- ^/help
- ^/contact_us
allowed_ips:
- 127.0.0.1
- 192.168.0.0/24

デプロイ前のチェックリスト

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

デプロイ手順

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

1
2
3
4
5
6
7
8
9
10
11
12
13
cap staging deploy:setup
cap staging deploy
> .... # <= 色々コマンドを実行
> servers: [server_ip]
> [server_ip:port] executing command
> command finished in XXXms # <= で成功

cap production deploy:setup
cap production deploy
> .... # <= 色々コマンドを実行
> servers: [server_ip]
> [server_ip:port] executing command
> command finished in XXXms # <= で成功

Apacheのバーチャルホストを設定

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

補足: yaml_dbでダンプしたデータをロードする処理を組込む

DBをダンプしたデータの取り込みをデプロイプロセスに追加したい場合はconfig/deploy.rbに以下を追加。

1
2
3
4
5
6
7
namespace :deploy do # namespaceは任意
  desc "Load the seed data from db/data.yml"
  task :dump_yml_load do
    run "cd #{current_path} && RAILS_ENV=#{rails_env} bundle exec rake db:load"
  end
end
after :deploy, "deploy:dump_yml_load"

もし、rakeコマンドでDBのダンプロードができるyaml_dbについて興味が有る方は、「yaml_db RailsのDBをコマンド一つでYAML形式でダンプ/ロードできるRubyGem」をご覧になってみて下さい。

補足: database.ymlをロードして値を使いたい場合

処理の中で、database.ymlの値を使ってmysqldumpなどの処理を実行したい場合の方法です。

config/deploy.rbにて以下のようにファイルを読み込みます。

1
2
3
4
5
6
7
8
9
10
namespace :db do
  desc "databaseをダンプ"
  task :dump do
    dbconfig = YAML.load(File.read('config/database.yml'))
    database = dbconfig[rails_env]["database"]
    password = dbconfig[rails_env]["password"]
    username = dbconfig[rails_env]["username"]
    run "cd #{current_path} && mysqldump -u #{username} -p\"#{password}\" #{database} > db/#{database}_dump.sql"
  end
end

Standalone ruby – How to load different environments from database.yml - Stack Overflow

補足: sh: xxx command not found/パスが通っていない場合

capistranoで実行中に、sh: xxx command not foundとパスの通っていないコマンドを実行する場合の対策です。

config/deploy.rbにPathを追加します。

1
2
3
set :default_environment, {
  'PATH' => "/opt/ruby-enterprise/bin/:$PATH"
}

Change PATH environment with Rails and Capistrano - It’s past my bedtime

Special Thanks

リンギオ - [Capistrano] ステージング環境にデプロイする

capistranoでssh越しのサーバーに設置する場合 - odeの開発メモ日記

はじめてのCapistrano #Rails #capistrano - Qiita

今日の雑記「iPhoneからMacにSSHでリモートログインする」|mattintosh note

powを使ってdevelopment以外のRAILS_ENVでRailsを起動する #Rails #Mac - Qiita

検証環境

今回の記事の検証環境は以下の通りです。

Local/Server:
  Ruby: 1.9.3
  Rails: 3.2.13

Local:
  OS: Mac Mountain Lion(OS X 10.8.2)
  Server App: Pow
  MySQL: 5.6.10

Server(さくらVPS 2Gプラン):
  CentOS: centos-release-6-2.el6.centos.7.x86_64
  Server app: Apache/2.2.15 (Unix)
  MySQL: 5.5.22

変更来歴

01/21 10:15 page_cache削除をdeploy/production.rbに追加
02/12 17:45 capistrano_rsync_with_remote_cacheを取り外し
04/22 18:30 Gem turnoutを追加、pow関連の記述ミスの修正
04/23 17:15 補足を2件追加

おすすめの書籍