この手の記事は、もう散々出尽くしている感が満載ですが、そんな記事を見ても1発で完了できず、微妙に考え方の違う複数ある記事をつまみ食いして死亡という、スキル不足な初心者にありがちなパターンを王道でいってしまったので、初心者が初心者に送る一つの道標になればと。
前提
- Capistrano v3.2.1
- Rails v4.1
- rbenv v0.4.0
- Ruby v2.1.2
- Unicorn v4.8.3
- Nginx v1.4.7
- Git
- GitHub
こんな感じで動作確認済み。
Webサーバ(nginx)とAppサーバ(unicorn)は同一のステージングサーバにデプロイするのを想定した構築メモです。GitでRailsアプリをバージョン管理し、ローカルからステージングサーバへCapistranoでGitリポジトリ経由でデプロイします。
設定
GitHub
GitHubからデプロイするためにDeploy keysを設定する必要があります。対象リポジトリページの「Settings」→「Deploy keys」に移動し、デプロイ対象サーバの公開鍵を登録します。
Gemライブラリ
デプロイに必要な部分のみ記載しておきます。適宜、アプリケーションに必要なものを追記してください。
gem 'dotenv-rails' #環境変数を簡単に扱うのに使用
group :development, :test do
gem 'capistrano', '~> 3.2.1'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano-bundler'
gem 'capistrano3-unicorn' #Unicornの起動を簡単に行える
end
group :production, :staging do
gem 'unicorn'
end
$ bundle install
人によっては、dotenv-rails
やcapistrano3-unicorn
は使わず、自前で行うかもしれないですが、これを使ったほうが楽だったので。
デプロイ設定
Capistranoは初期設定コマンドがあるので、それを使ってもいいんだけど、使わなくてもいいです。単に初期テンプレートファイルを作ってくれるだけなので。
$ bundle exec cap install
require 'capistrano/setup'
require 'capistrano/deploy'
# rbenvを使用している場合
require 'capistrano/rbenv'
# デプロイ先のサーバで、ユーザディレクトリでrbenvをインストールしている場合
set :rbenv_type, :user
set :rbenv_ruby, '2.1.2'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'
# Rails4から分離したsecrets.ymlの環境変数を .envファイルで管理する
set :linked_files, %w{config/secrets.yml .env}
# タスクを読み込むけど、今回は特に使わない
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
lock '3.2.1'
set :application, 'myapp'
set :repo_url, 'GitのリポジトリURL'
set :branch, 'master'
set :deploy_to, '/var/www/myapp'
set :scm, :git
set :log_level, :debug
set :pty, true
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets bundle public/system public/assets}
set :default_env, { path: "/usr/local/rbenv/shims:/usr/local/rbenv/bin:$PATH" }
set :keep_releases, 5
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
desc 'Restart application'
task :restart do
invoke 'unicorn:restart'
end
end
前述したsecret_key_baseを環境変数で設定するため、staging
の項目を追加するのみでOK。
development:
secret_key_base: bbbb # 適当
test:
secret_key_base: aaaa # 適当
staging:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
Railsアプリの稼働ディレクトリを仮に/var/www/myapp
と設定。
@app_path = '/var/www/myapp'
working_directory @app_path + "/current"
worker_processes 2
preload_app true
timeout 30
listen "/tmp/unicorn.sock", :backlog => 64
pid "/var/www/myapp/shared/tmp/pids/unicorn.pid"
stderr_path "#{@app_path}/log/unicorn.stderr.log"
stdout_path "#{@app_path}/log/unicorn.stdout.log"
before_fork do |server, worker|
ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile', ENV['RAILS_ROOT'])
end
before_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
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
end
end
end
after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
/config/environments/staging.rb
は、特に指定がなければproduction.rb
をそのままコピー。
Rails.application.configure do
config.cache_classes = true
config.eager_load = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.serve_static_assets = false
config.assets.js_compressor = :uglifier
config.assets.compile = false
config.assets.digest = true
config.log_level = :info
config.i18n.fallbacks = true
config.active_support.deprecation = :notify
config.log_formatter = ::Logger::Formatter.new
config.active_record.dump_schema_after_migration = false
end
デプロイ先のサーバ名とSSHのログインIDを指定。デプロイ元から、秘密鍵でデプロイ先サーバにアクセス可能なのが前提条件です。ssh_options
で鍵などの細かい指定は可能ですが、そのままでいけるなら、設定不要。
set :rails_env, "staging"
set :unicorn_rack_env, "staging"
role :app, %w{user@example.com}
role :web, %w{user@example.com}
role :db, %w{user@example.com}
server 'example.com', user: 'user', roles: %w{web app}
set :ssh_options, {
keys: %w(/home/vagrant/.ssh/id_rsa),
forward_agent: false,
auth_methods: %w(publickey)
}
ステージングサーバの環境構築
ステージングサーバ自体がRailsが稼働できるようにしておく必要があります。今どきならChefとかを使ってローカルでもステージングサーバでも同一の環境になっていたりすると思いますが。
環境変数の設定
ただ一つだけ、環境変数の管理を直接サーバで行っておきます。
SECRET_KEY_BASE="hogehoge"
staging:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
dotenvというGemライブラリを使っているのだけど、これで使い方が正しいのかはちょっと微妙…。
nginxの設定
nginxは単純にUnicornの前に立ってるだけなのでシンプル。
upstream unicorn_server {
server unix:/tmp/unicorn.sock
fail_timeout=0;
}
server {
listen 80;
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
# Location of our static files
root /var/www/myapp/public;
location ~ ^/assets/ {
root /var/www/myapp/shared/public;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://unicorn_server;
break;
}
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/myapp/public;
}
}
デプロイ実行
デプロイ自体は非常に簡単なコマンドです。
$ bundle exec cap staging deploy
実行前に、簡単なチェックも可能。
$ bundle exec cap staging deploy:check
これで、上手く行けばデプロイ先のステージングサーバにUnicornのプロセスが起動しているはずです。ps
コマンドで確認してみてください。
Unicornの停止と再起動とか
起動
$ bundle exec unicorn -c /var/www/myapp/current/config/unicorn/staging.rb -E deployment -D
停止
$ kill -QUIT `cat /var/www/myapp/shared/tmp/pids/unicorn.pid`
再起動
$ kill -HUP `cat /var/www/myapp/shared/tmp/pids/unicorn.pid`