Capistrano3で本番環境とステージング環境を切り替えて自動デプロイ。導入メモ。

CapistranoというRuby製のデプロイツールを導入してみたときのメモです。
このCapistranoはRailsのデプロイに人気のツールですが、PHPなどのRails以外のアプリもrailsless-deployなどを用いてプロイできます。

コマンド一つで複数あるサーバに一気にデプロイでき、マイグレーションなどまでできて非常に便利です。

以下、Ubuntu 14.04のローカル環境からFuelPHPのAWSのEC2インスタンスにGitHub上のコードをデプロイした時の導入手順です。FuelPHPではないRails以外のアプリもマイグレーションの指定以外は同じ方法でデプロイできると思われます。



# 環境構築
以下、ローカルで以下のコマンドを入力していく。

```bash
# Rubyのインストール(ruby2.0以上が必要)
$ sudo add-apt-repository -y ppa:brightbox/ruby-ng
$ sudo apt-get update
$ sudo apt-get -y install ruby2.1

# gemsのインストール
$ sudo apt-get install rubygems-integration

$ gem source -r https://rubygems.org/
$ gem source -a http://rubygems.org/

# Capistranoのデプロイに必要なもののインストール
$ sudo gem install net-ssh -v 2.9.2
$ sudo gem install capistrano railsless-deploy
$ sudo gem install bundler

$ sudo gem update --system
```



#Capistranoの準備
##Gemfileの作成
デプロイ対象のディレクトに移動して、Gemfileを作成する。以下の例のように記述する

```bash
$ vim Gemfile
```

Gemfileへの記述内容

```Gemfile
source "https://rubygems.org"

gem 'capistrano', '~> 3.4'
gem 'capistrano-composer', '~> 0.0.6'
gem 'capistrano-bundle_rsync'
```

##Capistranoのファイル作成

作成したGemfileと同じディレクトリで以下のコマンドを実行する

```bash
$ sudo bundle install
$ bundle exec cap install
```

すると、以下のようなディレクトが出来上がる。

```
- Capfile
- Gemfile
- Gemfile.lock
- config
    - deploy.rb
    - deploy
        - production.rb
        - staging.rb
```
config/deploy.rbに本番環境とステージング環境の共通する処理を記述し、config/deploy/production.rbをconfig/deploy/staging.rbにそれぞれ本番環境とステージング環境の個別処理を記述する。

config/deploy.rbの記述例は以下の通り。

```deploy.rb
lock '3.5.0'

set :branch, 'master'
set :application, '<アプリケーション名>'
set :repo_url, 'git@github.com:<アカウント名>/<レポジトリ名>.git'
set :deploy_to, '/var/www/<実際のEC2上のデプロイ先のパス>'
set :scm, :git
set :format, :pretty

set :linked_dirs, fetch(:linked_dirs, []).push('<デプロイ先のsharedでシンボリックリンクの参照先のファイル>')
set :keep_releases, 5

set :stages, %(production, staging)
set :default_stage, "staging"

namespace :deploy do
  task :migrate do
    on roles(:app) do
      execute "FUEL_ENV=#{fetch :stage} php #{deploy_to}/current/oil refine migrate"
    end
  end

  task :oil_install do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      # Here we can do anything such as:
      within release_path do
        execute :php, :oil, :refine, :install
      end
    end
  end
end

after 'deploy', 'deploy:migrate'
after 'deploy:finishing', 'deploy:oil_install'
```

上記の`task :migrate`部分の処理、`after 'deploy', 'deploy:migrate'`と、下記の環境毎の設定の`server`部分で指定しているrolesのdbはマイグレーションをするための設定であり、実際に上記でマイグレーションを実行する、`FUEL_ENV=#{fetch :stage}`は、FuelPHPにおいて環境毎の実行をするための設定で環境変数に対して、環境毎の設定ファイルで`:stage`に設定された環境を`fetch`で読み込んで設定するものとなっています。

本番環境とステージング環境の個別の処理の記述は以下の通りとなる。

```production.rb
server '<IP address1>', user: 'ec2-user', roles: %w{app web db}
server '<IP address2>', user: 'ec2-user', roles: %w{app web db}
                           :
               (サーバーの数だけ記述する)
                           :

set :stage, :production

set :ssh_options, {
  keys: ENV['DEPLOY_PRODUCTION_KEY'],
  forward_agent: true
}
```

```staging.rb
server '<IP address>', user: 'ec2-user', roles: %w{app web db}
                           :
               (サーバーの数だけ記述する)
                           :

set :stage, :staging

set :ssh_options, {
  keys: ENV['DEPLOY_STAGING_KEY'],
  forward_agent: false
}
```

`%w(~/.ssh/id_rsa.pem)`のように記述してもよい。

`:ssh_options`の`keys`には鍵のパスを指定する。
##`:ssh_options`のforward_agentについて
サーバに秘密鍵を置かないでデプロイ可能にするために以下の作業を行っておく。
サーバ上でssh-keygenで生成するなどして鍵が置かれてGitHubにsshできる状態の時はfalseにして以下の作業は行わなくても良い。

###1. (※) ローカルでSSH agentを立ち上げ秘密鍵の登録

```
$ eval "$(ssh-agent -s)" 
Agent pid XXXX
$ ssh-add ~/.ssh/id_rsa
Identity added: /Users/xxxxx/.ssh/id_rsa (/Users/xxxxx/.ssh/id_rsa)
$ ssh-add -l
2048 SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx /Users/xxxxx/.ssh/id_rsa (RSA)
```

###2. Capistranoでforward_agentの設定
ENV['DEPLOY_PROUDCTION_KEY']は秘密鍵のパス

```
set :ssh_options, {
  keys: ENV['DEPLOY_PROUDCTION_KEY'],
  forward_agent: true
}
```

###3. (※) GitHubにpullする対象となるレポジトリに公開鍵を登録する。
1. プロジェクトのトップページ(https://github.com/<レポジトリ名>/<プロジェクト名>)で
SettingsからDeploy keysを選択。

2. [add deploy key]を選択して、TitleにGitHub上のDeploy keysで表示される識別名(なんでもいい)を入力し、keyに公開鍵の中身(cat ~/.ssh/id_rsa.pubしたもの)を入力する。

###Capistranoで ```Permission denied (publickey)```
上記の公開鍵の設定があってないと以下のようなエラーが出る；。

```
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as ec2-user@<IP Address>: git exit status: 128
git stdout: Permission denied (publickey).
fatal: Could not read from remote repository.
```


# Capistranoの実行

```bash
# 本番環境へのデプロイ
$ bundle exec cap production deploy

# ステージング環境へのデプロイ
$ bundle exec cap staging deploy
```

環境変数で鍵のパスを指定したときは以下のように実行する。

```bash
# 本番環境へのデプロイ
$ DEPLOY_PRODUCTION_KEY='~/.ssh/id_rsa' bundle exec cap production deploy

# ステージング環境へのデプロイ
$ DEPLOY_STAGING_KEY='~/.ssh/id_rsa' bundle exec cap staging deploy
```
上のコマンドを一つ入力するだけで、本番環境もしくはステージング環境へのデプロイがマイグレーションも含めて実行できる。

ロールバックする場合は`deploy`の代わりに`deploy:rollback`を指定する。

##(追記) Composerインストール
本番環境でComposerがないと警告が出た時はEC2上に以下のコマンドが実行されるようにしておく。

```bash
$ curl -sS https://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer
```


#デプロイ先のファイル構成
実際のデプロイ先は、`:deploy_to`で指定したパスにCapistranoのディレクトリが構成されます。ディレクトリ構成は以下の通りとなる。

```
- current
- release
- repo
    - FETCH_HEAD
    - HEAD
    - branches
    - config
    - description
    - hooks
    - info
    - objects
    - packed-refs
    - refs
- revisions.log
- shared
```
`release`には過去のデプロイ履歴、
`current`には`release`の最新版へのシンボリックリンク、
`revisions.log`には過去のデプロイ歴のログ、
`shared`には`:linked_dirs`で指定したシンボリックリンクで参照するためのディレクトリ
が保存されます。



#参考
## 環境のセットアップ
http://higehiki.hateblo.jp/entry/2014/02/03/201105
http://blog.hrendoh.com/deploy-fuelphp-with-capistrano3-1/
http://doruby.kbmj.com/trinityt_on_rails/20100907/CakePHP_Capistrano_
http://shusatoo.net/programming/ruby/ruby-beginner-capistrano-deploy/
https://vesselinv.com/fuelphp-deployment-with-capistrano/

## マイグレーション
https://www.kaeruspoon.net/articles/350
http://nitamago-monster.hatenablog.com/entry/2014/11/28/192458
http://blog.hrendoh.com/deploy-fuelphp-with-capistrano3-2/#i-2
http://higehiki.hateblo.jp/entry/2014/02/03/201105

## デプロイ
http://blog.hrendoh.com/deploy-fuelphp-with-capistrano3-2/
http://qiita.com/mr-myself/items/2769676e6dcf43db41ef