開発したアプリなど一覧

Ubuntu 18.04 + Nginx + Unicorn な環境に Rails アプリを Capistrano でデプロイする

VPS のサーバーを移行したついでに Web サーバーを Apache から Nginx へ、Rails アプリの実行環境を Passenger から Unicorn へ移行する事にした。その影響でいろいろ設定などを書き換える必要があったのでメモ代わりに書いておこうと思う。

Rails アプリを Unicorn で動くようにする

Gemfile で unicorn を読み込むようにする

$ vim Gemfile
group :production do
  gem 'unicorn'
end

unicorn の設定ファイルを config/unicorn.rb に記述する。

$ vim config/unicorn.rb
APP_PATH   = "#{File.dirname(__FILE__)}/.." unless defined?(APP_PATH)
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
RAILS_ENV  = ENV['RAILS_ENV'] || 'development'
shared_path = '/home/ryomatsu/projects/example/shared'

worker_processes 3

listen "/tmp/example-com.sock"
pid "#{shared_path}/tmp/pids/unicorn.pid"

preload_app true

timeout 60
working_directory APP_PATH

# log
stderr_path "#{RAILS_ROOT}/log/unicorn_error.log"
stdout_path "#{RAILS_ROOT}/log/unicorn_access.log"

if GC.respond_to?(:copy_on_write_friendly=)
  GC.copy_on_write_friendly = true
end

before_exec do |server|
  ENV['BUNDLE_GEMFILE'] = APP_PATH + "/Gemfile"
end

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

  old_pid = "#{ server.config[:pid] }.oldbin"
  unless old_pid == server.pid
    begin
      Process.kill :QUIT, File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH

    end
  end
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

特に重要なのが pid と sock ファイルの場所。これらを利用して Unicorn の起動や停止、Nginx からの読み込みを行う。

Unicorn の起動は以下のコマンドで行える。

$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D

それから Apache では設定ファイル内に記述していた secret_key_base の記述もどこかにしておく。dotenv Gem を利用するのが良いらしいがとりあえず動作すればよいので config/secrets.yml に直接書いてしまった。後でどうにかするかも。

Unicorn で動く Rails アプリを Capistrano でデプロイする

自分の Rails アプリケーションは全て Capistrano を利用してデプロイしているため、Capfile や deploy.rb などを書き換える。

Capistrano を使って Rails アプリをデプロイする

unicorn を利用する際は capistrano3-unicorn Gem を利用すると楽っぽい。

GitHub - tablexi/capistrano3-unicorn

Gemfile に gem 'capistrano3-unicorn' を記述し bundle install でインストール、Capfile では capistrano3-unicorn を読み込むようにする。

$ vim Gemfile
# 以下を追記
gem 'capistrano3-unicorn'
$ vim Capfile
# 以下を追記
require 'capistrano3/unicorn'

次に config/deploy.rb を編集する。

$ vim config/deploy.rb
# 以下適当な場所に追記しておく。
set :unicorn_roles, ->{ :web }
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
set :unicorn_config_path, -> { File.join(current_path, "config", "unicorn.rb") }

after 'deploy:published', 'deploy:restart'

namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:web), in: :sequence, wait: 5 do
      #invoke 'unicorn:restart'
      invoke 'unicorn:stop'
      invoke 'unicorn:start'
    end
  end
end

capistrano3-unicorn では標準では role が :app のサーバーに対してのみ unicorn のタスクが実行できるようなので unicorn_roles で指定しておく。

pid は unicorn を再起動するのに必要となるので path を間違えないように。人によって shared/tmp/pids/ と current/tmp/ とで設定方法が分かれる。

本来は unicorn:restart を実行すると unicorn.pid を利用して kill -s USR2 コマンドを実行し unicorn が再起動されるはずなのだが、なんか上手くいかなかったので unicorn:stop と unicorn:start コマンドを実行している。

Nginx + Unicorn で Rails アプリを動かす

最後に Nginx で Unicorn を介して Rails アプリを動かすように設定しよう。例えば以下のような感じになる。

$ vim /etc/nginx/sites-available/example.com
upstream example-com {
        server unix:/tmp/example-com.sock;
}

server {
        listen 80;
        server_name example.com;
        return 301 https://$host$request_uri;
}

server {
        listen 443;
        ssl on;
        ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        server_name example.com;

        access_log  /var/log/nginx/example.com-access.log;
        error_log   /var/log/nginx/example.com-error.log;

        location / {
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header Client-IP $remote_addr;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_pass http://example-com;
        }

        location ~ ^/assets/  { root /home/ryomatsu/public_html/example.com/public; }
        location ~ ^/images/  { root /home/ryomatsu/public_html/example.com/public; }
        location ~ ^/uploads/ { root /home/ryomatsu/public_html/example.com/public; }

        location = /robots.txt  { log_not_found off; }
        location = /favicon.ico { log_not_found off; }
}
$ 
$
$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl restart nginx

一番上の upstream で Rails アプリ内で指定した sock ファイルと同じものを指定し、それを proxy_pass で渡す。そうすれば Nginx が Unicorn を経由して Rails アプリにアクセスできる。

assets や images などへアクセスする際には location で場所を指定する必要があったのでそれも記述している。

これで再起動して設定ファイルを読み込めば Web ブラウザから Rails アプリにアクセスできるはず。

正常に動作しない場合は nginx のログ /var/log/nginx/example.com-error.log や、unicorn のログ log/unicorn_error.log を確認しよう。

-- 参考リンク

capistrano3-unicorn/unicorn.rb at master · tablexi/capistrano3-unicorn · GitHub
Rails4+Capistrano3+Nginx+Unicorn EC2へのデプロイ < 前編 > - Qiita
Unicorn + nginx で複数の Rails アプリを動かす : あかぎメモ

Sponsored Link

コメント

タイトルとURLをコピーしました