はじめに
デプロイ作業をコマンドひとつで簡単に出来るようにするために、Ruby製のデプロイツールであるcapistranoを使ってみます。
今回は、AWSにアプリケーションがとりあえずサーバー構築出来た状態からCapistranoをセットアップしていきたいと思います。
以下の、2つの記事でVPCとEC2の構築と、unicornとnginxの導入が出来ている状態からセットアップしていきます。
AWS VPCによるネットワーク構築とEC2によるサーバー構築
RailsアプリケーションのAWSによる公開|unicorn + nginx
Rails5系の Nginx+Pumaの記事も書いているので5系の方はこちらをどうぞ↓
Rails5アプリケーションのAWSによるネットワーク構築 Nginx+Puma+Capistranoな環境とAWS構築(VPC EC2 RDS CloudFlont Route53 etc)
なお、上記記事と同様に「protospace」というアプリケーションをサーバーに「shizuma」というユーザーで作成していきます。
作業は、「local」と「server」の作業どちらか確かめながら進めて下さい。コマンドを記載したエリアの左端に記述しています。
また、改善点がありましたらコメント頂けますと幸いです。
Capistranoの導入
[protospace] vi Gemfile
-----------------------------
# gemファイルの中にunicorn、capistrano関連のgemを追記して下さい。
group :production, :staging do
gem 'unicorn'
gem 'capistrano'
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano3-unicorn'
end
-----------------------------
[protospace] bundle install
[protospace] bundle exec 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
-----------------------------
各種ファイルの編集
unicornの設定ファイル
[protospace] vi config/unicorn.conf.rb
# 以下のように記述
-----------------------------
# set lets
$worker = 2
$timeout = 30
$app_dir = "/var/www/rails/protospace/current" #自分のアプリケーション名、currentがつくことに注意。
$listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir
$pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir
# set config
worker_processes $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen $listen
pid $pid
# loading booster
preload_app true
# before starting processes
before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
old_pid = "#{server.config[:pid]}.oldbin"
if old_pid != server.pid
begin
Process.kill "QUIT", File.read(old_pid).to_i
rescue Errno::ENOENT, Errno::ESRCH
end
end
end
# after finishing processes
after_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
-----------------------------
Capfileの編集
[protospace] vi Capfile
-----------------------------
# Load DSL and set up stages
require 'capistrano/setup'
# Include default deployment tasks
require 'capistrano/deploy'
# Include 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
# https://github.com/capistrano/passenger
#
# require 'capistrano/rvm'
require 'capistrano/rbenv' #コメントアウトをはずす
# require 'capistrano/chruby'
require 'capistrano/bundler' #コメントアウトをはずす
require 'capistrano/rails/assets' #コメントアウトをはずす
require 'capistrano/rails/migrations' #コメントアウトをはずす
# require 'capistrano/passenger'
require 'capistrano3/unicorn' #追記
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob('lib/capistrano/tasks/*.task').each { |r| import r }
-----------------------------
capistrano/tasks/unicorn.taskの設定
[protospace] vi lib/capistrano/tasks/unicorn.task
# unicornのtaskの記述。unicornのセットアップです。
-----------------------------
namespace :unicorn do
task :environment do
set :unicorn_pid, "#{current_path}/tmp/pids/unicorn.pid"
set :unicorn_config, "#{current_path}/config/unicorn.conf.rb"
end
def start_unicorn
within current_path do
execute :bundle, :exec, :unicorn, "-c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D"
end
end
def stop_unicorn
execute :kill, "-s QUIT $(< #{fetch(:unicorn_pid)})"
end
def reload_unicorn
execute :kill, "-s USR2 $(< #{fetch(:unicorn_pid)})"
end
def force_stop_unicorn
execute :kill, "$(< #{fetch(:unicorn_pid)})"
end
desc "Start unicorn server"
task start: :environment do
on roles(:app) do
start_unicorn
end
end
desc "Stop unicorn server gracefully"
task stop: :environment do
on roles(:app) do
stop_unicorn
end
end
desc "Restart unicorn server gracefully"
task restart: :environment do
on roles(:app) do
if test("[ -f #{fetch(:unicorn_pid)} ]")
reload_unicorn
else
start_unicorn
end
end
end
desc "Stop unicorn server immediately"
task force_stop: :environment do
on roles(:app) do
force_stop_unicorn
end
end
end
-----------------------------
[protospace] vi config/deploy/production.rb
# production環境のサーバー情報
-----------------------------
#下記を追記する
server '00.00.000.000', user: 'shizuma', roles: %w{app} #serverのipとuser名は適宜
set :ssh_options, keys: '~/.ssh/first_aws_rsa' #ssh_keyの名前は適宜
-----------------------------
[protospace] vi config/deploy.rb
-----------------------------
# config valid only for current version of Capistrano
lock '3.4.0'
# アプリケーション名
set :application, 'protospace'
# deployするレポジトリ
set :repo_url, 'git@github.com:kuboshizuma/protospace.git'
# Default branch is :master
# deployするブランチ。デフォルトはmasterなのでなくても可。
set :branch, 'master'
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
# Default deploy_to directory is /var/www/my_app_name
# deploy先のディレクトリ
set :deploy_to, '/var/www/rails/protospace'
# Default value for :scm is :git
# set :scm, :git
# Default value for :format is :pretty
# set :format, :pretty
# Default value for :log_level is :debug
# set :log_level, :debug
# Default value for :pty is false
# set :pty, true
# Default value for :linked_files is []
# シンボリックリンクをはるファイル。今回はgemのconfigを使用して、production.ymlを共通化。
set :linked_files, fetch(:linked_files, []).push('config/settings/production.yml')
# Default value for linked_dirs is []
# シンボリックリンクをはるフォルダ。
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
# Default value for keep_releases is 5
# 保持するバージョンの個数
set :keep_releases, 5
# rubyのバージョン
set :rbenv_ruby, '2.1.3'
namespace :deploy do
desc 'Restart application'
task :restart do
invoke 'unicorn:restart'
end
desc 'Create database'
task :db_create do
on roles(:db) do |host|
with rails_env: fetch(:rails_env) do
within current_path do
execute :bundle, :exec, :rake, 'db:create'
end
end
end
end
desc 'Run seed'
task :seed do
on roles(:app) do
with rails_env: fetch(:rails_env) do
within current_path do
execute :bundle, :exec, :rake, 'db:seed'
end
end
end
end
after :publishing, :restart
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
# Here we can do anything such as:
# within release_path do
# execute :rake, 'cache:clear'
# end
end
end
end
-----------------------------
環境変数の設定
今回はconfigというgemを使っています。dotenvとかでもいいと思います。
この設定は適宜必要に応じて設定して下さい。(ただし、secret_key_baseの設定は必要になります。)
[protospace] vi config/database.yml
-----------------------------
production:
<<: *default
database: protospace_production
username: <%= Settings.database[:user_name] %>
password: <%= Settings.database[:password] %>
-----------------------------
[protospace] vi config/secret.yml
-----------------------------
production:
secret_key_base: <%= Settings.production[:secret] %>
-----------------------------
[protospace] rake secret RAILS_ENV=production
erfffer34gfdv19b5ec7523a23tgrege45gertf3d15b94dfgvere23r34g87253a6f6b7b80c6cb47c598e000500b4654143gergfwer3r4cca04d
[shizuma|protospace] mkdir -p shared/config/settings/
[shizuma|protospace] vi shared/config/settings/production.yml
-----------------------------
database:
user_name: 'root'
password:
production:
secret: 'erfffer34gfdv19b5ec7523a23tgrege45gertf3d15b94dfgvere23r34g87253a6f6b7b80c6cb47c598e000500b4654143gergfwer3r4cca04d'
-----------------------------
nginxの設定
releaseバージョンはcurrentディレクトリなので微調整。
[shizuma|~] sudo yum install nginx
[shizuma|~]$ cd /etc/nginx/conf.d/
[shizuma|conf.d]$ sudo vi protospace.conf
----------------------------
# log directory
error_log /var/www/rails/protospace/current/log/nginx.error.log; #currentつける
access_log /var/www/rails/protospace/current/log/nginx.access.log; #currentつける
# max body size
client_max_body_size 2G;
upstream app_server {
# for UNIX domain socket setups
server unix:/var/www/rails/protospace/current/tmp/sockets/.unicorn.sock fail_timeout=0; #currentつける
}
server {
listen 80;
server_name 127.0.0.1;
# nginx so increasing this is generally safe...
keepalive_timeout 5;
# path for static files
root /var/www/rails/protospace/current/public; #currentつける
# page cache loading
try_files $uri/index.html $uri.html $uri @app;
location @app {
# HTTP headers
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
# Rails error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/rails/protospace/current/public; #currentつける
}
}
----------------------------
[shizuma|protospace]$ sudo nginx -s reload # nginxの再起動
githubへ変更をpush
[protospace] git add .
[protospace] git commit -m "Add for deploy by capistrano"
[protospace] git push origin master
デプロイ
[protospace] bundle exec cap deploy production
これで、完了!
エラー対応
rails_config
gemでrails_configを使っていたが、エラーが出たので、configというgemに変更。
mysql2
バージョン指定で対応。
Rails mysql2でrake db:createがエラー問題
/tmp/mysql.sockエラー
シンボリックリンクで対応。
$ ln -s /var/lib/mysql/mysql.sock /tmp/mysql.sock
参考
AWSはこれで大丈夫|unicorn + nginx + capistrano + slackistrano のコマンド一覧