LoginSignup
13
16

More than 5 years have passed since last update.

CentOS7 + unicorn + nginx 設定メモ

Last updated at Posted at 2016-08-19

環境

  • CentOS Linux release 7.1.1503
  • Ruby on Rails 5.0.0.1
  • unicorn_rails v5.1.0
  • nginx/1.10.1

nginxのインストール

CentOS6

$ sudo rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
$ sudo yum install -y nginx

CentOS7

$ sudo yum install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
$ sudo yum install --enablerepo=nginx nginx

設定ファイル編集

{appname}の部分は任意。
/etc/nginx/conf.d/{appname}.conf

下記は最低限の設定。これだけでとりあえずrailsは動く。

/etc/nginx/conf.d/{appname}.conf
upstream rails-unicorn {
    # nginxのソケット保存先指定
    server unix:/home/vagrant/{appname}/tmp/sockets;
}

server {
    # port
    listen       80;
    # サーバーのIPアドレス
    server_name  192.168.33.10;

    # DocumentRoot
    root   /home/vagrant/{appname}/public;
    try_files $uri $uri.html $uri/index.html @rails-unicorn;

    # charset
    charset utf8;
    # logs
    access_log  /var/log/nginx/{appname}/{appname}.access.log  main;
    error_log  /var/log/nginx/{appname}/{appname}.error.log  error;

    location @rails-unicorn {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_pass http://rails-unicorn;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

nginxの実行ユーザー変更

実行ユーザーをnginxからvagrantに変更
/etc/nginx/nginx.conf

/etc/nginx/nginx.conf
user  vagrant;

(*snip*)

nginx起動

# 自動起動有効
$ sudo systemctl enable nginx
# 起動
$ sudo systemctl start nginx

unicronのインストール

Gemfileに下記追記

Gemfile
gem 'unicorn'

bundle install

$ bundle install --path vendor/bundle

configの下にunicorn.rbというファイルを作成する。
引用元:Unicorn設定のまとめ

config/unicorn.rb
# Railsのルートパスを求める。(RAILS_ROOT/config/unicorn.rbに配置している場合。)
rails_root = File.expand_path('../../', __FILE__)
# RAILS_ENVを求める。(RAILS_ENV毎に挙動を変更したい場合に使用。今回は使用しません。)
rails_env = ENV['RAILS_ENV'] || "development"

# 追記に記載してます。入れた方がいいです。
ENV['BUNDLE_GEMFILE'] = rails_root + "/Gemfile"

# Unicornは複数のワーカーで起動するのでワーカー数を定義
# サーバーのメモリなどによって変更すること。
#worker_processes
#Unicornは、リクエストを振り分ける一つのmasterプロセスと、実際にリクエストを処理する複数のworkerプロセスで構成されるアーキテクチャになっている。
#worker_processesはworkerプロセスの数を指定する。
#実際のアプリのメモリ使用量などを見ながらworker数を調節できるように、環境変数を指定できるようにしてあるとのこと。
worker_processes 2

# 指定しなくても良い。
# Unicornの起動コマンドを実行するディレクトリを指定します。
# (記載しておけば他のディレクトリでこのファイルを叩けなくなる。)
working_directory rails_root

# 接続タイムアウト時間
timeout 30

# Unicornのエラーログと通常ログの位置を指定。
stderr_path File.expand_path('../../log/unicorn_stderr.log', __FILE__)
stdout_path File.expand_path('../../log/unicorn_stdout.log', __FILE__)

# Nginxで使用する場合は以下の設定を行う。
listen File.expand_path('../../tmp/sockets/unicorn.sock', __FILE__)
# とりあえず起動して動作確認をしたい場合は以下の設定を行う。
listen 8080
# ※「backlog」や「tcp_nopush」の設定もあるけど、よくわかって無い。

# プロセスの停止などに必要なPIDファイルの保存先を指定。
pid File.expand_path('../../tmp/pids/unicorn.pid', __FILE__)

# 基本的には`true`を指定する。Unicornの再起動時にダウンタイムなしで再起動が行われる。
preload_app true
# 効果なしとの記事を見たので、コメントアウト。
# GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

# USR2シグナルを受けると古いプロセスを止める。
# 後述するが、記述しておくとNginxと連携する時に良いことがある。
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
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, 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

unicorn起動

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

unicorn起動スクリプト例

lib/tasks/unicorn.rake
namespace :unicorn_rails do
  RAILS_ENV=ENV['RAILS_ENV']
  UNICORN_CMD='unicorn_rails'
  UNICORN_CONFIG=%Q(#{File.dirname(File.expand_path(__FILE__))}/../../config/unicorn/#{ENV['RAILS_ENV']}.rb)
  UNICORN_PID=%Q(#{File.dirname(File.expand_path(__FILE__))}/../../tmp/pids/unicorn.pid)

  task :environment do
  end

  desc 'unicorn_rails start'
  task :start => :environment do

    sh %Q(/bin/bash -lc "bundle exec #{UNICORN_CMD} -c #{UNICORN_CONFIG} -E #{RAILS_ENV} -D")
  end

  desc 'unicorn_rails stop'
  task :stop => :environment do 
    if %x(ps ho pid p `cat #{UNICORN_PID}`).present?
      sh %Q(kill `cat #{UNICORN_PID}`)
    end
  end

  desc 'unicorn_rails graceful_stop'
  task :graceful_stop => :environment do
    if %x(ps ho pid p `cat #{UNICORN_PID}`).present?
      sh %Q(kill -s QUIT `cat #{UNICORN_PID}`)
    end
  end

  desc 'unicorn_rails reload'
  task :reload => :environment do
    if %x(ps ho pid p `cat #{UNICORN_PID}`).present?
      sh %Q(kill -s USR2 `cat #{UNICORN_PID}`)
    else
      Rake::Task['unicorn_rails:start'].execute
    end
  end

  desc 'unicorn_rails restart'
  task :restart => :environment do
    if %x(ps ho pid p `cat #{UNICORN_PID}`).present?
      Rake::Task['unicorn_rails:stop'].execute
    else
      puts %Q(unicorn didn't work.)
    end
    Rake::Task['unicorn_rails:start'].execute
  end
end

capistrano task用

lib/capistrano/tasks/unicorn.rake
namespace :unicorn_rails do
  task :environment do
    set :unicorn_cmd, 'unicorn_rails'
    set :unicorn_config, "#{current_path}/config/unicorn/production.rb"
    set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
  end

  desc 'unicorn_rails start'
  task :start => :environment do
    on roles(:app), reject: lambda { |h| h.properties.no_release } do
      execute "cd #{current_path} && bundle exec #{fetch(:unicorn_cmd)} -c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D"
    end
  end
  task :stop => :environment do
    on roles(:app), reject: lambda { |h| h.properties.no_release } do
      if test("[ -f #{fetch(:unicorn_pid)} ]")
        execute "kill `cat #{fetch(:unicorn_pid)}`"
      end
    end
  end
  task :graceful_stop => :environment do
    on roles(:app), reject: lambda { |h| h.properties.no_release } do
      if test("[ -f #{fetch(:unicorn_pid)} ]")
        execute "kill -s QUIT `cat #{fetch(:unicorn_pid)}`"
      end
    end
  end
  task :reload => :environment do
    on roles(:app), reject: lambda { |h| h.properties.no_release } do
      if test("[ -f #{fetch(:unicorn_pid)} ]")
        execute "kill -s USR2 `cat #{fetch(:unicorn_pid)}`"
      else
        Rake::Task['unicorn_rails:start'].execute
      end
    end
  end
  task :restart => :environment do
    on roles(:app), reject: lambda { |h| h.properties.no_release } do
      Rake::Task['unicorn_rails:stop'].execute
      Rake::Task['unicorn_rails:start'].execute
    end
  end
end

unicorn自動起動設定

起動スクリプトの作成

/etc/init.d/unicorn
#!/bin/bash

#chkconfig:2345 85 70
#description:unicorn shell

USER='rails_user'
RAILS_ROOT='/path/to/rails_app/current'
NAME='unicorn_rails'
PID="${RAILS_ROOT}/tmp/pids/unicorn.pid"

start()
{
  if [ -e $PID ]; then
    PID_NUM=`cat ${PID}`
    PROCESS=`ps ho pid p ${PID_NUM} > /dev/null; echo $?`
    if [ "${PROCESS}" != 0 ]; then
      echo 'rm ghost pid'
      rm -f ${PID}
    else
      echo "$NAME already started"
      exit 1
    fi
  fi
  echo "start $NAME"
  su - $USER -lc "cd ${RAILS_ROOT} && bundle exec rake unicorn_rails:start"
}

stop()
{
  if [ ! -e $PID ]; then
    echo "$NAME not started"
    exit 1
  fi
  echo "stop $NAME"
  su - $USER -lc "cd ${RAILS_ROOT} && bundle exec rake unicorn_rails:stop"
}

force_stop()
{
  if [ ! -e $PID ]; then
    echo "$NAME not started"
    exit 1
  fi
  echo "stop $NAME"
  kill -INT `cat ${PID}`

}

reload()
{
  if [ ! -e $PID ]; then
    echo "$NAME not started"
    start
    exit 0
  fi
  echo "reload $NAME"
  #kill -HUP `cat ${PID}`
  su - $USER -lc "cd ${RAILS_ROOT} && bundle exec rake unicorn_rails:reload"
}

restart()
{
    stop
    sleep 3
    start
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  force-stop)
    force_stop
    ;;
  reload)
    reload
    ;;
  restart)
    restart
    ;;
  *)
    echo "Syntax Error: release [start|stop|force-stop|reload|restart]"
    ;;
esac
$ sudo chkconfig --add unicorn
$ sudo chkconfig on
$ sudo chkconfig --list

参考

13
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
16