オレオレ capistrano TIPS: database.yml の設置/unicorn を使う/db:create をリモートから実行する

capistrano を使って rails アプリをデプロイしようとすると、ちょっとしたところでつまづきます。

今日は、最近僕が躓いたこと/調べたことをいくつか書いてみたいと思います。

database.yml を設置する

database.yml にはパスワードなどの扱いに困る情報が載っているので、リポジトリにコミットしたくないファイルのひとつです。
また、開発環境は本番環境などで設定が違うのでどうやってデプロイするか悩みます。

capistrano の wiki ページ では "Managing `database.yml` Securely" と称してこのページが紹介されています。
でも、もう少し調べていくと、実はこのコードは capistrano_database_yml という名前でリリースされています。

というわけで、capistrano_database_yml を使ってみます。

インストール

さっくり gem コマンドで入れます。

$ gem install capistrano_database_yml

capistrano で使うために config/deploy.rb に書き足します。

require 'database_yml/capistrano'

おしまいです。

使ってみる

capistrano_database_yml は二種類の動きをします。

ひとつは deploy:setup のときに #{deploy_to}/shared/config/database.yml を作るというものです。
標準では sqlite を使うダミーの設定を作ってくれます。
もし他の内容にしたい場合は config/deploy/database.yml.erb にファイルを置いておくと、
その内容を #{deploy_to}/shared/config/database.yml に配置してくれます。

もうひとつのアクションはデプロイ終了時に #{deploy_to}/shared/config/database.yml を
config/database.yml として設置してくれます。


あらかじめスケルトンを config/deploy/database.yml.erb に設置しておいて、
deploy:setup を実行した後に必要情報を書き足す。
そして通常の deploy を繰り返す。
という流れで使うことができます。

アプリケーションサーバunicorn を使う

Web や gist の情報を元に、config/deploy.rb にいろいろ unicorn 用のタスクを書きまくっていたのですが、
capistrano-unicorn というモジュールがあることに気づきました。

インストール

さっくり gem コマンドで入れます。

$ gem install capistrano-unicorn

capistrano で使うために config/deploy.rb に書き足します。

require 'capistrano/unicorn'
after 'deploy:start', 'unicorn:start'
after 'deploy:stop', 'unicorn:stop'

標準では deploy:restart 用しか見てくれないので、deploy:start と deploy:stop 用のフックを登録しておきます。

使ってみる

unicorn 用の設定ファイルを config/unicorn/ 以下に設置します。
RAILS_ENV の値と同じ、development.rb, test.rb, production.rb の 3つを用意しておけば問題ありません。
もう少し細かく調整したい方は、説明やコードを読んでみてください。

あとは通常通り deploy するだけで unicorn を使ったデプロイをすることができます。

データベースを初期化する

何度も実行するものではないのでタスクに登録すべきか迷ったのですが、作業をシンプルにするために
データベース初期化作業を capistrano task にしてみました。

db:drop, db:create, db:migrate, db:seed を次々実行するだけのものです。

namespace :deploy do
  namespace :db do
    desc "Create Database"
    task :create, {:roles => :db, :only => {:primary => true}} do
      run "cd #{current_path} && bundle exec rake db:create RAILS_ENV=#{rails_env}"
    end

    desc "Create Database"
    task :drop, {:roles => :db, :only => {:primary => true}} do
      run "cd #{current_path} && bundle exec rake db:drop RAILS_ENV=#{rails_env}"
    end

    desc "Load seed data"
    task :seed, {:roles => :db, :only => {:primary => true}} do
      run "cd #{current_path} && bundle exec rake db:seed RAILS_ENV=#{rails_env}"
    end

    task :init, {:roles => :db, :only => {:primary => true}} do
      tasks = %w(deploy:update_code
                 deploy:create_symlink
                 db:symlink
                 deploy:db:drop
                 deploy:db:create
                 deploy:migrate
                 deploy:db:seed)

      agree = Capistrano::CLI.ui.agree("deploy:db:init will DROP your database. Are you sure? (Yes, No)") do |q|
        q.default = 'No'
      end

      transaction do
        tasks.each do |name|
          task = top.find_task(name)
          invoke_task_directly_without_callbacks(task)
        end
      end
    end
  end
end

これを config/deploy.rb に書いておくと、アプリケーションの初回設置が

$ cap deploy:setup
$ vi shared/config/database.yml
$ cap deploy:db:init
$ cap deploy:cold

だけで済むようになる、すぐれもののタスク(自称)です。

よくある内容だと思うので、既に gem パッケージになっているのではないかと思ったのですが、
ブログは見かけても、パッケージ化されたものは見つけられませんでした。

追記(2013/2/16): capistrano-rails-dbinit としてパッケージ化しました。