capistrano3を利用してRails4をdeployしunicornを使う
December 2, 2014
Rails v4.1.2
capistrano v3.3.3
TL;DR
cap3でrails4のデプロイとbundle install
unicornの操作をできるようにするまでのメモ
手元のマシンでcap3をインストール
$ gem install capistrano
Railsアプリケーションのあるパスに移動
$ cd app_name
cap install
$ cap install
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified
$
app_name/config
配下にdeploy用の各種設定テンプレートが格納され、
独自rake taskを格納するapp_name/lib/capistrano/tasks/
ディレクトリが作成され、
capistrano用の設定ファイル?であるCapfileのひな形が作成される.
deployの設定
config/deploy.rb
汎用的な設定はここに書くのかな
lock '3.3.3'
# 自分のアプリケーション名
set :application, 'app_name'
# 自分のリポジトリ名.capistranoはrsyncではなくgit pullする
set :repo_url, 'git@github.com:kenjiskywalker/app_name.git'
# デプロイ先
set :deploy_to, '/home/foo/app_name'
# cap stage unicorn:start などの実行対象の role . デフォルトは app
set :unicorn_roles, :all
set :ssh_options, {
# ここのオプションは ssh_config に記載されていれば不要
# port: 2222,
# keys: [File.expand_path('~/.ssh/hoge.key')],
}
# ここは cap install するとコメントアウトで入るのでそのコメントアウトを解除
set :linked_dirs, fetch(:linked_dirs, []).push('bin', 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
config/deploy/stage.rb
汎用的な設定はdeploy.rbに書き、stage毎の設定はstage.rbに書くのかな
- config/deploy/development.rb
# RAILS_ENV の指定
set :rails_env, 'development'
# unicorn で利用する RACK_ENV の指定
set :unicorn_rack_env, 'development'
# ここの user も ssh_config に記載されていれば不要
server 'dev-web1', user: 'foo', roles: %w{web}
- config/deploy/staging.rb
# RAILS_ENV の指定
set :rails_env, 'staging'
# unicorn で利用する RACK_ENV の指定
set :unicorn_rack_env, 'staging'
# ここの user も ssh_config に記載されていれば不要
server 'stg-web1', user: 'foo', roles: %w{web}
- config/deploy/production.rb
# RAILS_ENV の指定
set :rails_env, 'production'
# unicorn で利用する RACK_ENV の指定
set :unicorn_rack_env, 'production'
# ここの user も ssh_config に記載されていれば不要
server 'web1', user: 'foo', roles: %w{web}
Gemfile
capistranoで利用するgemを追加
group :development, :staging, :production do
gem 'capistrano'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano-bundler'
gem 'capistrano3-unicorn'
gem 'unicorn'
end
Capfile
consoleとbundlerとunicornを有効化
# Load DSL and Setup Up Stages
require 'capistrano/setup'
# Includes default deployment tasks
require 'capistrano/deploy'
require 'capistrano/console' # cap stage console とかやると便利
# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
# https://github.com/capistrano/rvm
# https://github.com/capistrano/rbenv
# https://github.com/capistrano/chruby
# https://github.com/capistrano/bundler
# https://github.com/capistrano/rails
#
# require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
require 'capistrano/bundler' # deploy:updated の前に bundle install してくれる
require 'capistrano3/unicorn' # cap3で unicorn を操作できるようにしてくれる
# require 'capistrano/rails/assets'
# require 'capistrano/rails/migrations'
# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
config/unicorn/stage.rb
:unicorn_config_path を参考にすると
config/unicorn.rb
ではなくconfig/unicorn/satge.rb
を記載する
unicorn 設定例 : example.rb
上記設定例を参考に設定.取り敢えず変更箇所はapp_path
ぐらい
- config/unicorn/stage.rb
# paths
app_path = "/home/foo/app_name"
working_directory "#{app_path}/current"
pid "#{app_path}/current/tmp/pids/unicorn.pid"
# listen
listen "/tmp/hoge-api.socket", :backlog => 64
# logging
stderr_path "log/unicorn.stderr.log"
stdout_path "log/unicorn.stdout.log"
# workers
worker_processes 3
# use correct Gemfile on restarts
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "#{app_path}/current/Gemfile"
end
# preload
preload_app true
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
# Before forking, kill the master process that belongs to the .oldbin PID.
# This enables 0 downtime deploys.
old_pid = "#{server.config[:pid]}.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
動作チェック
deploy
$ bundle exec cap development deploy:check
$ bundle exec cap development deploy
$ bundle exec cap staging deploy
$ bundle exec cap production deploy
unicorn
$ bundle exec cap development unicorn:start
$ bundle exec cap development unicorn:legacy_restart
$ bundle exec cap development unicorn:stop
学び
rsyncではなくgit pullなので混乱することがある.
currentやrelease, sharedなど見たらわかる面白構造.
当たり前だけど上手くいかない時は手を動かすよりドキュメントとコードを読んだ方が早い.
以上簡単なメモです.