読者です 読者をやめる 読者になる 読者になる

Capistrano 3への手引き

Capistrano、便利ですよね。

capistrano/capistrano

最近メジャーバージョンアップがあったのですが、使い方、というかスクリプトの書き方やお作法が変わり、「Capistrano 3にアップデートしたはいいけど全然動かなくてどうなってんだ」という流れはもはやお約束みたいです。

試しに僕も個人で作ってるウェブサイトのCapistranoをアップデートしてみたので、その上でこんなところに気を付けたいな、と思うポイントでも書いておきます。

capifyは使わない

Capistranoを使うときは$ bundle installをし、次に$ bundle exec capify .とするのがお約束の流れですが、これからはcapifyを使ってもcap installを使ってねと言われます。

ですので:

$ bundle exec cap install

としましょう。

マルチステージが最初から有効になっている

ひとつのスクリプトで複数の環境(ステージ)にデプロイするときは今までcapistrano/capistrano-extcapistrano/ext/multistageを使うのが常套手段でしたが、これはデフォルトで有効になっています*1

デフォルトで有効であるため、cap installを行うと、Capfileとconfig/deploy.rbという今まで通りのものに加え、config/deploy/staging.rbとconfig/deploy/production.rbが作られます。もしconfig/deploy/*に書き出されるステージ名を変えたい場合は:

$ bundle exec cap install STAGES=development,staging,production

とSTAGES環境変数でcap install渡してあげましょう。

Capistrano拡張の対応

Ruby on Rails然りですが、これだけバージョンが変われば、今まで使ってきた拡張も使えなくなるというものです。

ただいくつかの拡張に関してはcapistrano自身が対応させた拡張を公開していますので、そちらを使いましょう。

# Gemfile
source 'https://rubygems.org'

group :development do
  gem 'capistrano'
  gem 'capistrano-rbenv', github: 'capistrano/rbenv'
  gem 'capistrano-bundler', github: 'capistrano/bundler'
  gem 'capistrano-rails'
end

capistrano-railsは「Capistranoは別にRuby on Railsだけのものじゃないんだよ」を体現するために別扱いになりました。こちらはrubygems.orgにあるため、githubオプションなどでgitリポジトリを指定する必要はありません。

また、これらの拡張は今まで人によってconfig/deploy.rbなどにrequireを記述していたかもしれませんが、Capfileに書くのが通例のようです。実際、cap installによって生成されたCapfileには上記の拡張がコメントアウトされています。必要に応じてコメントアウトを外しておきましょう。

変数の参照

今まで:

set :application, 'example-app'

として設定した変数は直接applicationとローカル変数のように参照できていましたが、これからは出来ません。fetchメソッドを使いましょう。

set :deploy_to, "/u/apps/#{fetch(:application)}"

なお、current_pathなどは変数とはまた別の扱いらしく、今まで通りローカル変数のように参照できます。

変数名の変更

「なんで変えたんだ!」と言いたくなる気がしますが、repository変数はrepo_url変数と名前が変わりました。拡張ではありますが、capistrano/rbenvの場合、rbenv_pathではなくrbenv_type(:systemで/usr/local/rbenv、:userで~/.rbenv)で、rbenv_ruby_versionはrbenv_rubyになりました。

大きな変更というより、Capistrano開発者の好みの範囲での変更に思えてしまいますが、ドキュメント参照の上、適切に設定する必要がありそうです。

デプロイ先のサーバの設定

今までは下記のように書いていました。

role :app, 'app1.example.com', 'app2.example.com'
role :web, 'web1.example.com'
role :db, 'db1.example.com', primary: true

Capistrano 3でも上記記述でエラーが出るわけではないのですが、公開鍵での認証が出来なくなってしまいました。以下のように書くのがベターな気がします。

server 'app1.example.com', roles: %w(app), user: 'deploy', ssh_options: {
  keys: [File.expand_path('~/.ssh/...')]
}

正直ここら辺はよく調べていないのですが、サーバごとに認証を設定できたりする方が理に適っていて、個人的にはこちらの方が好きです。

共有ディレクトリの設定

Capistranoはdeploy_toの配下にcurrent, releases, sharedの3つのディレクトリを作成します*2

その中のsharedにはデプロイの度に上書きを避けたいファイルなどをディレクトリにまとめて置き、デプロイ時にそのディレクトリへシンボリックリンクを張るという処理が行なわれていました。そのシンボリックリンクを張るディレクトリはshared_childrenという変数で設定できていたのですが、それがlinked_dirsに変わりました。ちなみにlinked_filesという変数も追加されています。

ただ名前が変わっただけなら良いのですが、ちょっとディレクトリ構造が変わることがあるので、注意が必要です。具体的には:

set :shared_children, %w(public/system)

とすると、deploy:setup時にshared/systemが作成され、そのディレクトリがreleases/LATEST_RELEASE/public/systemとしてシンボリックリンクを作成するような動作になっていましたが、Capistrano 3では:

set :linked_dirs, %w(public/system)

とすると、shared/systemではなく、shared/public/systemが作成されるようになります。ですので、Capistrano 2から乗り換えた場合、サーバ側でちょっと手を加えてあげないと今まで参照できていたファイルが参照できない、などといったことが発生するため注意が要ります。

各タスクの記述

ここが一番大きな変更点だと思います。今までtaskメソッドを呼び出してタスクを定義し、そのメソッドへのオプションでどのロールで実行するのか、などを定義していました。タスクの中では愚直にrunを並べて、そのタスクが何を行うのかを記述していました。何度もrunを呼びたくないからと、コマンドを組み立て、runメソッド1回で全コマンドを実装するように心掛けていた人もいるんじゃないかと思います。

Capistrano 3では基本taskメソッドはタスク名しか渡さず、その中のonメソッドでいろいろ記述します。

task :example do
  on roles(:app), in: :sequence, wait: 5 do
    # ~
  end
end

そしてonメソッドに渡したブロックの中で実行するコマンドなどを記述していきます。

コマンドの記述

先述のように、onメソッドに渡したブロックの中にコマンドを記述するのですが、ここで様々なメソッドが使えるようになっています。

namespace :log do
  task :clear do
    on roles(:app), in: :parallel do

      # 渡したパスが存在するかを確かめ、存在しなければブロック内のコマンドを実行しない。
      # また、コマンド実行時に先頭に"cd 渡したパス && "を付与する
      within current_path.join('log') do

        # コマンド実行時に先頭に環境変数の設定を付与する。
        # 下記の例では"RAILS_ENV=rails_env変数の値"となる
        with rails_env: fetch(:rails_env) do

          # コマンドの実行成否を真偽値で取得する(元々あった?)
          if test '[ -f development.log ]'

            execute :rm, 'development.log'

           end

        end

      end

    end
  end
end

他にもasなどがあるのですが、これらはleehambley/sshkitというSSHによるコマンドの実行を構造的に記述するためgemの仕業です。タスクの記述方法然り、コマンドの記述方法然りなのですが、ここらへんの記述方法が変わったのはSSHKitを導入したからなのかなあ、と思います。

SSHKitを使えばexecuteをもっとスマートに書けたりするので、ぜひ活用していきたいところです。ちなみにonメソッドもSSHKitのものですね。

deploy:setup

なくなりました。いきなりdeployで大丈夫です。他にもいくつかタスクの名前が変わっていたりします。

他にもまだまだたくさんありそうですが、というかcap installで作成されたスケルトンから読み取れることしか書いてないのですが、とりあえずこんなところで。

*1:ていうか2.xのいつからかcapistrano-ext使わなくても有効でしたよね?

*2:Capistrano 3ではrepoも加わりました。単にcloneやpullをするための(サーバから見て)ローカルリポジトリです