Edited at

AWS RailsアプリケーションのCapistranoによるデプロイ

More than 1 year has passed since last update.


はじめに

デプロイ作業をコマンドひとつで簡単に出来るようにするために、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の導入


local

[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の設定ファイル


local

[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の編集


local

[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の設定


local

[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
-----------------------------


local

[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の名前は適宜
-----------------------------


local

[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の設定は必要になります。)


local

[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



server

[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ディレクトリなので微調整。


server

[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


local

[protospace] git add .

[protospace] git commit -m "Add for deploy by capistrano"
[protospace] git push origin master


デプロイ


local

[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 のコマンド一覧