Capistrano3のデプロイフレームワークの使い方

[Capistrano](http://www.capistranorb.com/)はバージョン3から汎用的なデプロイフレームワークになりました。タスクのフックを利用することで簡単に自分のアプリケーション環境に特化したデプロイプロセスを記述することができます。

本稿では、この汎用化されたデプロイ機能の使い方に焦点を絞って解説したいと思います。より基本的なCapistrano3の解説は

* [入門 Capistrano 3 ~ 全ての手作業を生まれる前に消し去りたい | GREE Engineers' Blog](http://labs.gree.jp/blog/2013/12/10084/)

がよくまとまっているので、そちらを参考にしてください。この参考記事では "5. Capistranoデフォルトタスクの消去" でCapistranoの新規導入時のコストを下げる目的で、このフレームワーク機能を消去しています。本稿はこのフレームワーク機能の使い方を解説するものです。

## deployとframeworkの2つの抽象度が用意されている

Capistrano3をインストールするといきなりこんな感じのCapfileが作られます

```rb:Capfile
# Capistranoの設定を読み込む。おまじない
require 'capistrano/setup'

# デプロイフレームワークを読み込み
require 'capistrano/deploy'

# `lib/capistrano/tasks' に定義されたタスクを読み込む
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
```

この[capistrano/deploy](https://github.com/capistrano/capistrano/blob/master/lib/capistrano/deploy.rb)が内部で[capistrano/framework](https://github.com/capistrano/capistrano/blob/master/lib/capistrano/framework.rb)を読み込みます。つまり、Capistrano3のデプロイ機能には2つのレベルが存在しています。

1.   capistrano/framework

     もっとも汎用的なデプロイフレームワーク。デプロイの開始、コードのアップデート、システムの公開、デプロイの完了、という流れを定義しているだけで具体的な処理は一切含まない。フックを提供するだけ

2.   capistrano/deploy

     より具体的なタスクが追加されたもの。デプロイ可能かのチェック、デプロイ先ディレクトリの存在確認などなど、ほとんどのデプロイ時に必須になるデプロイ環境の準備系のタスクが定義されている。

Capistrano3のデプロイフレームワークを利用する場合は、capistrano/frameworkのタスクにRake由来の `before` や `after` を使って自アプリケーションに固有の処理を埋め込んでいくことで実装します。

## capistrano/frameworkが提供するデプロイの流れ

```bash
% cat Capfile
require 'capistrano/setup'
require 'capistrano/framework'
% cap -T
cap deploy                     # Deploy a new release
cap deploy:finished            # Finished
cap deploy:finishing           # Finish the deployment, clean up server(s)
cap deploy:finishing_rollback  # Finish the rollback, clean up server(s)
cap deploy:published           # Published
cap deploy:publishing          # Publish the release
cap deploy:reverted            # Reverted
cap deploy:reverting           # Revert server(s) to previous release
cap deploy:rollback            # Rollback to previous release
cap deploy:started             # Started
cap deploy:starting            # Start a deployment, make sure server(s) ready
cap deploy:updated             # Updated
cap deploy:updating            # Update server(s) by setting up a new release
cap install                    # Install Capistrano, cap install STAGES=staging,production
```

だいたい分かると思いますが `cap staging deploy` を実行すると下記の順序で空のタスクが実行されます。

1.  deploy:starting
2.  deploy:started
3.  deploy:updating
4.  deploy:updated
5.  deploy:publishing
6.  deploy:published
7.  deploy:finishing
8.  deploy:finished

そして `cap staging deploy:rollback` を実行すると下記の順序で実行します。

1.  deploy:starting
2.  deploy:started
3.  deploy:reverting
4.  deploy:reverted
5.  deploy:publishing
6.  deploy:published
7.  deploy:finishing_rollback
8.  deploy:finished

これらは全て中身の無い、空のタスクです。これらの前後にタスクを埋め込んでいくことでデプロイプロセスを記述していきます。

## capistrano/deployが提供するデプロイの流れ

capistrano/frameworkよりもう一歩踏み込んでデプロイフローを提供するのがcapistrano/deployです。

`cap staging deploy` すると下記のような順序でタスクが実行されるようになります。

1.  deploy:starting
    1.  deploy:check
        1.  git:check
        2.  deploy:check:directories
        3.  deploy:check:linked_dirs
        4.  deploy:check:make_linked_dirs
        5.  deploy:check:linked_files
2.  deploy:started
3.  deploy:updating
    1.  git:create_release
    2.  deploy:symlink:shared
        1.  deploy:symlink:linked_files
        2.  deploy:symlink:linked_dirs
4.  deploy:updated
5.  deploy:publishing
    1.  deploy:symlink:release
6.  deploy:published
7.  deploy:finishing
    1.  deploy:cleanup
8.  deploy:finished

個々のタスクの内容について詳しくは説明しませんが、名前から判断するにcapistrano/deployがcapistrano/frameworkが提供するデプロイフローのセマンティックにあうように、タスクを追加していることが分かります。

例えば、deploy:startingでデプロイ先のディレクトリの準備などは全てcapistrano/deployがやってくれるので、deploy:startedに紐付けるタスクはディレクトリが存在する前提で記述してOKな訳です。

ちなみにここでgit:checkなどのようにGitをVCSとして利用しているのはあくまでもデフォルト値であって、hgを使ったり、他のツールを指定することもできます（その場合はそのツールに対してVCS:checkなどのタスクを用意する必要があります）

## 具体例: HipChat通知する

例えばデプロイ開始時と終了時ににHipChatのDevルームに通知したい、という場合は

```rb:lib/capistrano/tasks/hipchat_notification.rb
require 'hipchat'

client = HipChat::Client.new(HIPCHAT_TOKEN)['Dev']

namespace :hipchat do
  namespace :update do
    task :start do
      run_locally do
        client.send('Deploy', 'デプロイ開始')
      end
    end

    task :finish do
      # ..
    end
  end

  namespace :rollback do
    # ..
  end
end

before 'deploy:updating', 'hipchat:update:start'
after 'deploy:finishing', 'hipchat:update:finish'
before 'deploy:reverting', 'hipchat:rollback:start'
after 'deploy:finishing_rollback', 'hipchat:rollback:finish'
```

のように書けばよい訳です。capistrano/frameworkを骨格にして、各々のタスクが肉付けをしていくことで、それぞれのタスクを疎に保ちながらデプロイプロセスを記述することができます。