rbenv+Rails+Passenger+capistrano+capistrano-ext入門


この記事の所要時間: 1645
Webアプリケーションのデプロイ作業1回の1つ1つの作業内容自体は単純ですが、設定ファイルの書き換えが煩雑な上に地味に時間を食うために、人為的なミスを誘発しやすくなります。このデプロイ作業でミスって原因不明の動作不良に悩まされたことは誰にでもあるかと思います。このような単調で時間のかかるデプロイ作業を自動化するツールの一つがcapistranoとなります。

Rails界では言わずと知れたデプロイツール。
数年前は意外と苦労することが多かったですが、最近は資料も豊富なので入門は比較的容易です。
少し資料が古くなっているようなので最新のRails用に整理しました。
Rails4で確認していますが、Rails3でも動くはずです。

サーバーサイドではrbenv+Phusion Passengerを使用しています。
capistranoはcapistrano-extを組み合わせています。
capistrano-extはステージング環境やプロダクション環境といった環境ごとに違ったデプロイ設定を記述できるcapistrano拡張です。
もちろんcapistranoだけでも動きますが、デプロイ先サーバーを気軽にスイッチできないのでcapistranoだけだとあまり旨味がありません。是非入れておきましょう。

認証方式はGitリポジトリ、デプロイ先サーバー共に公開鍵認証方式を採用します。
Gitリポジトリはパスフレーズあり、デプロイ先サーバーはパスフレーズなしとします。デプロイ先サーバーはCentOSとします。

構成するファイルは4つのファイルになります。以下はステージング環境用の設定ファイルを準備する例です。本番用の設定ファイルを準備したい場合はconfig/deploy/production.rbを追加で用意すればOKです。

  • Capfile
  • Gemfile
  • config/deploy.rb
  • config/deploy/staging.rb

重要なポイントはcapistranoが動くのはローカルPCのみで、デプロイ先サーバーにはcapistranoが入っている必要がないこと、もっと言えばRubyが入っている必要性すらないということです。これはPHPのWebアプリケーションをデプロイすることも可能であるということを意味します。実際にPHPアプリやJavaアプリをcapistranoでデプロイした実績があります。
ただし、当然ですが、capistranoを叩くPC側ではRubyが入っていないと動かないので注意が必要です。

capistrano+capistrano-extのインストール

以下の記述を追加します。

# Gemfile
# Use Capistrano for deployment
group :development do
  # capistrano
  gem 'capistrano', group: :development
  # multistage extension
  gem 'capistrano-ext', group: :development
  # rbenv extension
  gem 'capistrano-rbenv', group: :development
end

して

bundle install

初期化

以下のコマンドでCapfileとconfig/deploy.rbのひな形が生成されます。これを編集します。

bundle exec capify .

Capfile

Rails3系からはアセットパイプラインが有効になっているので load ‘deploy/assets’ の行のコメントを外します。

# Capfile
load 'deploy'
# Uncomment if you are using Rails' asset pipeline
load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks

config/deploy.rb

deploy.rbには共通の設定を記述します。ちょっと行数が多いですが、1行1行読みといて行きたいと思います。

# config/deploy.rb
# -*- coding: utf-8 -*-
#
# とても参考になる記事:
# * http://d.hatena.ne.jp/tetsuyai/20100910/1284051562
# * http://www.slideshare.net/T2J/capistrano-tips-tips
# * http://ringio-blog.appspot.com/2010/07/capistrano-deploy-to-staging-environment
# * http://log.miraoto.com/2012/07/633/
# * http://tk0miya.hatenablog.com/entry/2013/02/18/115433
#

# capistrano-ext を使いますよという宣言
# 何気に忘れがちなので注意
# これを書かないとcapしたときに
#     the task <code>staging' does not exist
# と言われるようになってしまう。
require 'capistrano/ext/multistage'

# rbenv setting
require 'capistrano-rbenv'
set :rbenv_ruby_version, '2.0.0-p0'
namespace :rbenv do
  task :setup_shellenv do
    set :default_environment, {
      'RBENV_ROOT' =&gt; &quot;#{rbenv_path}&quot;,
      'PATH' =&gt; &quot;#{rbenv_path}/shims:#{rbenv_path}/bin:$PATH&quot;,
    }
  end
  after 'multistage:ensure', 'rbenv:setup_shellenv'
end

# bundlerのcapistrano拡張を使うぞという宣言
require 'bundler/capistrano'

set :application, &quot;Hoge&quot;
# リポジトリの指定
set :repository,  &quot;git@github.com:wnoguchi/example.git&quot;

set :scm, :git # You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
# Or: </code>accurev<code>, </code>bzr<code>, </code>cvs<code>, </code>darcs<code>, </code>git<code>, </code>mercurial<code>, </code>perforce<code>, </code>subversion<code> or </code>none<code>

# デプロイ先サーバーのSSHユーザー名を指定(gitリポジトリのユーザー名ではない)
# 以下の場合はexampleユーザーでログインすることを意味します
set :user, 'example'
# CentOSなのでsudoコマンドを使用しない
set :use_sudo, false
# プッシュ式デプロイを使用する場合
#set :deploy_via, :copy
# デプロイ先のサーバーのSSHポート番号を指定
# デフォルト22番の場合はデフォルトで22が指定されるので必要ない
set :ssh_options, :port =&gt; '22'

# capistrano-extによって以下の記述は
# config/deploy/{staging,production}.rb に外だしされる。
# 2013-07-05 del noguchi start
#role :web, &quot;your web-server here&quot;                          # Your HTTP server, Apache/etc
#role :app, &quot;your app-server here&quot;                          # This may be the same as your </code>Web<code> server
#role :db,  &quot;your primary db-server here&quot;, :primary =&gt; true # This is where Rails migrations will run
#role :db,  &quot;your slave db-server here&quot;
# 2013-07-05 del noguchi end

# if you want to clean up old releases on each deploy uncomment this:
# after &quot;deploy:restart&quot;, &quot;deploy:cleanup&quot;

# if you're still using the script/reaper helper you will need
# these http://github.com/rails/irs_process_scripts

# これはアップロードされたファイル等を格納するディレクトリが毎回デプロイするたびに
# 空っぽになってしまうことを避けるための対策です。
# sharedディレクトリ直下に実ディレクトリを配置してcurrent以下にシンボリックリンクを張ります。
after &quot;deploy&quot;, &quot;deploy:link_files&quot;

# If you are using Passenger mod_rails uncomment this:
# Phusion Passengerを使用するので以下の行のコメントブロックを解除する
namespace :deploy do
  task :start do ; end
  task :stop do ; end
  task :restart, :roles =&gt; :app, :except =&gt; { :no_release =&gt; true } do
    run &quot;#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}&quot;
  end
  task :link_files do
    run &lt;&lt;-CMD
      cd #{shared_path} &amp;&amp;
      mkdir -p files &amp;&amp;
      cd #{release_path} &amp;&amp;
      rm -rf #{release_path}/files &amp;&amp;
      ln -nfs #{shared_path}/files #{release_path}/files
    CMD
  end
end

set :deploy_via, :copy はpush式デプロイを行う場合に使用します。push式デプロイとはcapistranoを実行するPCにリポジトリのデータを引っ張ってきてそれをデプロイサーバーにぶん投げる方法をとります。
通常はデプロイ先サーバーが自主的にリポジトリにSSHアクセスしてgit checkoutしてきます。セキュリティ上の制約がある場合にこのコメントを外します。

config/deploy/staging.rb

いきなり本番環境にプログラムをデプロイすることは少ないと思います。ステージング環境で動作確認を行い、問題がなければ本番環境に適用するといったプロセスを踏みます。デプロイ環境を変えるごとにこれらの設定ファイルの書き換えを行うのはかなり煩雑なので、環境ごとの設定ファイルを用意して自動化したいと思います。

環境ごとの設定を記述するファイルがこれになります。これはcapistrano-extのになう役割となります。ファイルは自分で一から作成しないといけません。といっても、deploy.rbの内容から環境ごとの設定をコピーしてそれをひな形とすれば大丈夫です。

重要なポイントその2

role :db で指定するホスト名はrake db:migrateを実行するサーバーを意味します。データベースサーバーのホスト名を指定するわけではないことに注意してください。

# config/deploy/staging.rb
# -*- coding: utf-8 -*-

#
# capistrano-ext 環境依存設定ファイル
# ステージング環境
#

# チェックアウトするブランチ名を指定する
set :branch, 'staging'
# RAILS_ENV で指定する環境名
# ステージング環境= RAILS_ENV=testと勘違いしていたのですが、
# testはユニットテスト等用の環境なのでステージング環境用途ではdevelopmentモードで動かすらしいです(同僚談)
# なのでstagingブランチを切ってそこにステージング用の設定をdevelopmentに記述する感じになりますかね。
set :rails_env, 'development'
# アプリケーションデプロイ先のベースディレクトリの絶対パスを記述する
set :deploy_to, '/home/example/app/development/'

# Your HTTP server, Apache/etc
role :web, &quot;example.unicast.ne.jp&quot;
# This may be the same as your </code>Web` server
role :app, &quot;example.unicast.ne.jp&quot;
# This is where Rails migrations will run
# rake db:migrateを実行するサーバーのホスト名を指定する
# データベースサーバーのホスト名になるわけではないので注意
role :db,  &quot;example.unicast.ne.jp&quot;, :primary =&gt; true

デプロイする

デプロイ前準備

まず以下のコマンドでベースとなるディレクトリをセットアップします。
(いつも当たり前のようにやっていたのでこの手順を掲載するのを忘れていました。すみません。)
この手順をやらないとsharedディレクトリ直下のassets, log, pids, systemといった大事なディレクトリが作成されないのでcurrent下に張られたシンボリックリンクがリンク切れを起こして、今後の作業で絶対に動きません。

bundle exec cap staging deploy:setup

初回デプロイ&マイグレーション

実際にデプロイする準備が完了しました。
初回のデプロイ時には以下のコマンドを叩きます。
こいつは一緒にdb:migrateタスクも一緒に実行してくれるので、マイグレーションファイルができたときにもcoldコマンドを叩きます。capistranoでdb:resetとかdb:fixtures:loadタスクとか実行できたらいいなあと思っているのですが、これはのちのち調べるようですね。

bundle exec cap staging deploy:cold

rbenvを使用する場合はgemの管理にbundlerを一緒に使用する場合が多いと思いますが、bundle installはこのタイミングで行われます。パス指定で以下にインストールされます。

/home/example/app/development/shared/bundle

すべてのgemは以上のディレクトリにインストールされたものが起動されます。PassengerもBundlerでインストールする設定をした場合は

bundle exec passenger-install-apache2-module

を手動で実行する必要があります。

日々のデプロイ作業

ソースのちょっとした変更等はdeployコマンドですませます。Passengerのインスタンス再起動まで自動でやってくれます。便利。

bundle exec cap staging deploy

トラブルシューティング

cap staging deploy:coldが途中で全然進まないんだけど・・・

bundle installとかに時間がかかるとデプロイサーバー側で接続維持のパケット送らないとSSH接続が切断されてずっとcapistranoは死なないようです。困ったちゃんです。以下を試してみてください。

# vi /etc/ssh/sshd_config
#ClientAliveInterval 0
# ↓ 変更
ClientAliveInterval 30

参考にしたサイト

ベースになる情報がよくまとまっています。

今から4年も前にできたスライドですが、今でも色褪せない使える沢山のTipsが掲載されていてなにか困ったらまず参照する必携のスライドとなっています。

capistrano+rbenvでのハマりどころ。

投稿者紹介

株式会社ユニキャスト
私たちは、テクノロジに魅せられた個性あふれるメンバーによって構成された茨城県日立市に本社を構えるベンチャー企業です。
”テクノロジを通して「驚き」と「感動」を創造し、人々の「夢」と「笑顔」を支えます。” の経営理念をモットーに明るい未来を描き、ワクワクする企画提案を続けて参ります。

人気の記事

コメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

PAGE TOP