Ruby on Rails を Capistrano で自動デプロイできるように Ubuntu を設定する機会があったので、作業内容を忘れないようにメモ。 Rails
、nginx
、MySQL
、Unicorn
の構成。ゴールは Ubunut 14.04 にCapistrano で Rails プロジェクトをデプロイできる こと。
追記: 以下の内容を少しリファクタリングして、 Ansible というツールを利用して自動化しました。( [Capistrano ですぐにデプロイできる Rails 環境を Ansible で自動構築する] (http://qiita.com/shimashima/items/b7c18c4489db3fcb3cbc) ) ほぼ下に書いた内容と同様のことを設定ファイルを10行くらい編集すれば出来ます。Capistrano の設定ファイルのサンプル も配置してあるので、時間が無い場合はこちらのほうが早いと思います。
内容
以下のことができる人にはこの記事は不要な情報かもしれません。その場合は次の記事に進んでいただくことでライフハックしていただければと思います。
- パスワードなし sudo の設定 (Capistranoで必要なので)
- rbenv のインストール (Rubyのバージョン管理で必要なので)
- MySQL のインストール (DBはMySQLで)
- Nginx の設定 (Apacheよりは今はこっちが主流?)
- github にデプロイ鍵を登録
- unicorn や database.yml や Capistrano 関連のファイルの設定
1. パスワードなし sudo の設定
パスワードなし sudo
ができないと Capistrano デプロイができない(今はそうでもないかも?)。
すでにパスワードなしで sudo ができる場合は不要
- この次の操作を間違えると二度と sudo ができなくなるので、先に root のパスワード設定
sudo su
passwd
# 新規パスワードを入力
- visudo でsudo権限の設定を変更
sudo visudo # 編集画面へ
# 設定ファイルの最後に以下の一行を追加 username はユーザ名
# username ALL=(ALL:ALL) NOPASSWD:ALL
2. rbenv を入れる
Ruby 自体のバージョン管理に利用。これで開発環境とデプロイ後の環境で ruby のバージョンが違うから動かない、みたいなことを回避できる。
- レポジトリ情報を更新
sudo apt-get update
- 必要なパッケージのインストール
sudo apt-get install -y git git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev
- rbenv のインストール
cd # ホームディレクトリへ移動
git clone git://github.com/sstephenson/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
- 正しくインストールされたことを確認
rbenv-install -l
# rbenv でインストールできる ruby のバージョンのリストが表示される
3. rbenv を用いて ruby をインストール
rbenv-install 2.2.0
# 結構時間がかかる
- 正しくインストールできたのを確認
rbenv versions
# 2.2.0 と表示されるはず。
- おそらく bundle が入ってないのでインストール
rbenv global 2.2.0 # インストールしたバージョンを指定
rbenv exec gem install bundle # 'rbenv exec' いらないかも。
# これで rbenv exec bundler が使えるようになったはず
4. MySQL の準備
- MySQL 関連のパッケージをインストール
sudo apt-get install -y mysql-server mysql-client libmysqld-dev
# MySQL の root ユーザのパスワードを聞かれるので適当に。
- Rails で使うユーザと DB を作成
mysql -u root -p
# root ユーザのパスワードでログイン
# データベース作成
CREATE DATABASE rails_database;
# ユーザ作成(rails_user の部分とrails_password を変えてください)
CREATE USER 'rails_user'@'localhost' IDENTIFIED BY 'rails_password';
# データベースの権限を作ったユーザに与える
GRANT ALL PRIVILEGES ON rails_database.* TO 'rails_user'@'localhost';
# 以上の設定を反映
FLUSH PRIVILEGES;
5. database.yml に上記のデータベースの設定を反映
上で設定した MySQL のデータベースやユーザ名、パスワードを設定。
default: &default
adapter: sqlite3
pool: 5
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
test:
<<: *default
database: db/test.sqlite3
production:
adapter: mysql2
encoding: utf8
reconnect: false
database: rails_database
pool: 5
username: rails_user
password: rails_password
host: localhost
6. nginx の準備
- インストール
sudo apt-get install nginx
cp /etc/nginx/sites-available/default /etc/nginx/sites-available/your_site.conf
vim /etc/nginx/sites-available/your_site.conf
# 下の設定ファイルを参考に変更
ln -s /etc/nginx/sites-available/your_site.conf /etc/nginx/sites-enabled/your_site.conf
- Nginx の設定ファイル
3行目のunix:...
の部分の socket の指定が unicorn の設定と一致するように注意する。
upstream app {
# Path to Unicorn SOCK file, as defined previously
server unix:/var/www/your_site.com/shared/tmp/sockets/unicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name your_site.com, www.your_site.com;
# Application root, as defined previously
root /var/www/your_site.com/current/public;
try_files $uri/index.html $uri @app;
location @app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
7. github にデプロイ鍵を登録
- 鍵がなければ鍵を作成する
ssh-keygen
# エンター、エンター、エンター
cat ~/.ssh/id_rsa.pub
# 出てきた文字を右クリックでコピー
# github のプロジェクトの設定から deploy key を選んで登録
8. Gemfile に必要な Gem を記述
- MySQL、unicorn、Capistrano に必要な Gem を加える
# 下記のものを追加
# Use Unicorn as the app server
gem 'unicorn'
# MySQL adopter
gem 'mysql2', '~> 0.3.13'
group :development, :test do
# for Capistrano
gem 'capistrano'
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano-rbenv', '~> 2.0'
gem 'capistrano3-unicorn'
end
9. Unicorn の設定ファイルを記述
- socket の部分が上記の nginx の設定と噛み合っていないと2回目以降に Capistrano デプロイしたときに、プロセスが新しいものに更新されないので注意
- pid も後述する Capistrano の設定ファイルの unicorn_pid パラメータと一致させることを忘れずに。
# path
app_path = '/var/www/your_site.com'
current_path = "#{app_path}/current"
shared_path = "#{app_path}/shared"
working_directory current_path
pid File.expand_path('tmp/pids/unicorn.pid', shared_path)
listen File.expand_path('tmp/sockets/unicorn.sock', shared_path), :backlog => 64
# logging
stderr_path "#{app_path}/shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/shared/log/unicorn.stdout.log"
# preload
preload_app true
# Number of processes
worker_processes 4
# Time-out
timeout 30
# use correct Gemfile on restarts
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "#{app_path}/current/Gemfile"
end
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
10. Capistrano の設定
deploy.rb
にすべてのサーバに共通する設定を記述。config/deploy/production.rb
などに環境ごとの詳細設定を記述するようにする。
# Load DSL and set up stages
require 'capistrano/setup'
# Include default deployment tasks
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
# config valid only for current version of Capistrano
lock '3.4.0'
# Multistage deployment extension
set :application, 'your_site.com'
set :repo_url, 'git@github.com:your_account/your_site.git'
set :rbenv_ruby, '2.2.0'
set :rbenv_type, :user
set :deploy_to, "/var/www/#{fetch(:application)}"
shared_path = "#{fetch(:deploy_to)}/shared"
release_path = "#{fetch(:deploy_to)}/current"
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :keep_releases, 10
# Unicorn
# unicorn.rb で指定した pid と一致するように。
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
set :unicorn_config_path, "#{release_path}/config/unicorn.rb"
set :ssh_options, {
keys: %w(~/.ssh/id_rsa),
forward_agent: false,
auth_methods: %w(publickey)
}
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
task :restart do
invoke 'unicorn:restart'
end
end
server 'yor_site.com', user: 'username', roles: %w{app db web}
set :unicorn_pid, "/var/www/#{fetch(:application)}/shared/tmp/pids/unicorn.pid"
set :stage, :production # これいらないかも。
set :unicorn_rack_env, 'production'
set :unicorn_config_path, "/var/www/#{fetch(:application)}/current/config/unicorn/production.rb"
set :rails_env, 'production'
set :branch, 'master'
最後: Capistrano でデプロイ!
プロジェクトの app
などがあるディレクトリで Rails プロジェクトをデプロイできる....かもしれない。
bundle exec cap production deploy