capistranoでRailsアプリケーションをdeployする

**注意!!こちらの記事はCapistrano2系の内容です!!**

# capistranoのインストール

Gemfileに下記を追記し、bundle installを実行する。

```rb:
# Gemfile
group :deployment do
  gem 'capistrano'
  gem 'capistrano-ext' # 環境毎に設定を変更するためのgem
  gem 'capistrano_colors' # capistrano実行時に色をつけるためのgem
  gem 'capistrano_rsync_with_remote_cache' # deploy時にrsyncを使うためのgem
end
```

```bash:
$ bundle install
```

# 初期化

gemをインストールすると、capifyコマンドが使用できるようになる。
capifyコマンドを実行すると、設定ファイルが作成される。

```bash:
$ bundle exec capify .
[add] writing './Capfile'
[add] writing './config/deploy.rb'
[done] capified!
```

# 設定ファイル編集

## 基本的な設定項目

公式ドキュメントはこちら。
https://github.com/capistrano/capistrano/wiki/2.x-Significant-Configuration-Variables

### アプリ名の定義

```rb:
set :application, 'myapp'
```

### deploy先のパスを設定

```rb:
set :deploy_to, '/path/to/app'
```

### hostの設定

下記は一つのサーバを一辺にまとめて定義する方法。

```rb:
server "localhost", :app, :web, :db, :primary => true
```

細かくroleを指定することも可能。

```rb:
role :web, 'localhost'
role :web, '127.0.0.1'
role :db, 'localhost', :master => true
```

roleを指定してtaskの実行が可能。

```rb:
# webのroleに設定されているhostに対して実行
task :sample, :roles => :web do
  # ...
end

# dbのroleでなおかつ、masterオプションがtrueのhostに対して実行
task :sample2, :roles => :db, :only => {:master => true} do 
  # ...
end
```

### stageの設定

deploy先の環境の定義。
capistranoコマンドを実行するとき、下記の環境を指定できるようになる。

```rb:
set :stages, %w(production staging)
set :default_stage, "staging"
```

```bash:
$ bundle exec cap staging deploy
$ bundle exec cap production deploy
```

### バージョン管理の設定

下記では、subversionを指定しているが、gitやmercurialなども指定できる。

```rb:
set :repository,  "Repository URL"
set :scm, :subversion
set :scm_username, "username"
set :scm_password, "password"
```

### デプロイユーザーの設定

```rb:
set :user, 'app'
set :password, 'password'
ssh_options[:keys] = "~/.ssh/id_rsa"
set :use_sudo, false
```

### 世代管理数

```rb:
set :keep_releases, 5
```

### deploy方法の設定

下記では、普段よくつかうrsync_with_remote_cacheを設定している。
この他に、copyやremote_cacheなども指定できる。

```rb:
set :deploy_via, :rsync_with_remote_cache

# deploy方法がrsync_with_remote_cacheのため、
# rsync時に除外するファイルや、オプションを設定する
set :copy_exclude, %W(
  .svn
  **/.svn
  .git
  **/.git
  .bundle/
  .gitignore
  .ruby-version
)
set :rsync_options, '-rtlvz --delete --delete-excluded ' +
  copy_exclude.map{|e| "--exclude='#{e}'"}.join(' ')
```

## 環境依存の設定を分割する

applicationやdeploy_toなどは、環境によって設定する値が変わってくる。
そのため、共通して使用できる設定は、config/deploy.rbに書き、環境に依存する設定は別ファイルに逃がしてあげる必要がある。

この仕組は、capistrano-extというgemがすでに用意してくれている。

### 環境依存ファイルを作成する

staging用の設定であれば、config/deploy/staging.rbに、
production用の設定であれば、config/deploy/production.rbを作成するだけである。

```config/deploy/production.rb
set :application, "production app name"
set :deploy_to, '/path/to/app/production'
set :rails_env, 'production'
role :web, 'web01'
role :web, 'web02'
role :db, 'db01'
```

```config/deploy/staging.rb
set :application, "staging app name"
set :deploy_to, '/path/to/app/staging'
set :rails_env, 'staging'
server "localhost", :app, :web, :db, :primary => true
```

## 最終的な設定ファイル

https://gist.github.com/tanihiro/6060400
https://gist.github.com/tanihiro/6060419

いくつかtaskを追加して、unicornやdatabaseの設定ファイルをsharedに逃がして、シンボリックリンクを設定したり、capistrano経由でunicornのプロセス操作を行えるようにした。

# deployのセットアップ

設定ファイルの記入が完了したら、デプロイの前準備をする。
capistranoが予め提供してくれている、deploy:setupコマンドを実行し、デプロイに必要なディレクトリをリモートの環境に作成しする。

```bash:
$ bundle exec cap staging deploy:setup
```

deploy:setupコマンドを実行すると、下記のようなディレクトリが **deploy_to** で指定したディレクトリに作成される。

```
.
├── releases
└── shared
    ├── log
    ├── pids
    └── system
```

# ディレクトリ構成の概要

capistranoによるdeployは世代管理ができるディレクトリ構成になっている。

### releases

releasesディレクトリに、ソースコードが格納される。
この時、deployの度にtimestampでディレクトリが作成される。

```
─── releases
    ├── 20130723024019
    ├── 20130723024428
    └── 20130723024445
```

### shared

releasesに作成された各ディレクトリで共通で使用したいファイルなどを格納するためのディレクトリ。
例えば、logなどはreleasesの各ディレクトリに書きだされてしまうと、デプロイの度に、ログファイルが別れてしまうので、実態ファイルはsharedに設置し、releases内のログファイルはshared内のログファイルにシンボリックリンクを設定する。

```
/deploy_to/releases/20130723024445/log -> /deploy_to/shared/log
```

### current

releases内に作成された最新のディレクトリに、シンボリックリンクを設定し、currentとして設置する。
WEBサーバからは、このcurrentをDocumentRootに設定する。
そうすることで、別のreleasesのディレクトリにシンボリックリンクを切り替えれば、簡単に前のバージョンのソースコードに戻したりすることが可能になる。

```
/deploy_to/current -> /deploy_to/releases/20130723024445
```

# deployを実行

deployの実行は、deployコマンドを実行する。
この時の挙動は、 **deploy_via** で指定したモードによって異なる。

```bash:
$ bundle exec cap staging deploy
```

## rsync_with_remote_cacheの場合

rsync_with_remote_cacheの挙動は簡単にまとめると、下記の順序で処理が進む。

1. ローカルの.rsync-cacheディレクトリに、ソースをチェックアウト、もしくは最新のソースの反映
2. ローカルの.rsync-cacheディレクトリから、リモートのshared/cached-copy/ディレクトリにrsyncで転送
3. リモートのサーバ内で、cached-copyディレクトリから、releasesにrsyncで転送
4. ソース転送後の処理を実行(shared内でbundle installなど)
5. 最新のreleaseディレクトリに、currentのシンボリックリンクを切り替える

※ ローカルのどこにソースをチェックアウトするかは、deploy.rbの **local_cache** を設定することで変更することができる。

## copyの場合

deploy実行の度に、バージョン管理から最新のソースをエクスポートし、圧縮させてからscpで転送→解凍を実行する。

## remote_cacheの場合

rsync_with_remote_cacheは、ローカルでチェックアウトし、rsyncでshared/cached-copyに転送していたのに対し、remote_cacheはリモートで直接shared/cached-copyにチェックアウトを実行する。
以降は、アップデートを行うため、毎回チェックアウトする手間が省ける。

# その他のcapistranoコマンド

下記を参照。
https://github.com/capistrano/capistrano/wiki/Capistrano-Tasks