Unicorn設定のまとめ


はじめに

NginxとUnicornでRailsサーバーを構築する必要が出てきたので、その時のメモを残しておきます。

この後Nginxと接続に関する記事を書いて、最終的にCapistranoでアップする手順を記載します。

注意

僕は環境周りがとても苦手なので、以下の点に関して誤っている点があるかもしれません。

Unicornのインストール

Unicornのインストールは以下をGemfileに記載してbundle installで行います。

Gemfile
gem 'unicorn'

Unicornの設定ファイル

Unicornの設定ファイルは大体以下のようになります。
説明は設定ファイル内にコメントとして記載してます。

参考:
Rails4.2 を Nginx + 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 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

起動する

とりあえず、ローカルで起動するなら上記のファイルを配置してRAILS_ROOTで以下のコマンドを叩きます。

$ bundle exec unicorn_rails -c config/unicorn.rb

また、以下のコマンドでも起動します。

$ bundle exec unicorn -c config/unicorn.rb

unicornunicorn_railsの違いはRACKで動かすかRAILSで動かすかの違いです。
RAILSRACK上で動いているため、どちらのコマンドでも起動します。

細かい点で挙動に違いがあります。
以下のURLが参考になると思います。
unicornとunicorn_railsのオプションの違い

動けば良いという方はunicorn_railsを使いましょう。
また、-Dオプションをつければデーモン化されます。
-EをつければRailsの環境オプションに合わせて起動します。(ここがunicornunicorn_railsで違う挙動をします。)

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

ブラウザから以下のURLでアクセスできることが確認できると思います。

http://localhost:8080

Unicornの停止/再起動

こちらのサイト通りです。

以下、転記します。

停止コマンド

$ kill -QUIT `cat /path/to/unicorn.pid`

再起動コマンド

$ kill -HUP `cat /path/to/unicorn.pid`

緩やかな再起動コマンド

$ kill -USR2 `cat /path/to/unicorn.pid`

こちらの処理を行う際にbefore_forkpreload_app trueが役立ちます。
このコマンドを叩くと新プロセスを立ち上げて旧プロセスを停止します。
一時的に新旧両方のプロセスが立ち上がる事でダウンタイムをなしの状態を作り出せます。

before_forkを記載してないと、旧プロセスがずっと残ってしまいます。
preload_app trueを記載しないと自分自身が再起動されます。(未確認)

CapistranoでUnicornを使う場合

別記事でまとめる予定だが、以下のgemを使用すると簡単に使える。

Gemfile
gem 'capistrano3-unicorn'

上記をインストールして以下で使用する。

Capfile
require 'capistrano3/unicorn'

中身を見ればわかるが、これは自分自身でも作る事ができる。
また、起動コマンドがunicornになってるので注意が必要である。

僕が犯したミス

僕はcapistrano3/unicornが何ものかわからなかったため、require 'capistrano3/unicorn'unicorn.rakeを両方書いてしまい、二重にunicornが立ち上がってしまうという恥ずかしいミスをしてしまった・・・。
しかも、中身を追わなかったため原因の解明にとても時間がかかった・・・。
(ちゃんと中身は見るべきですね。)

capからrakeへ

どうでも良い事だが、CapistranoのTaskが*.capから*.rakeに変わってた。
引っかかって、構築に時間がかかった・・・
(unicorn.capというファイルを作って、読み込まれないなぁ・・・って思ってた。)

Railsのログローテーションについて

こちらが参考になります。
Ruby on Rails - Unicorn のログローテーション!

最後に

僕は環境構築を一度したら、その後なかなか環境構築を行わない。
前の時はPassengerApacheに設定したらその設定を使いまわしてアプリケーションを作ってしまうため、環境周りが本当に苦手である。

なので、僕のためにもこの記事が必要だった。
この記事が僕のような環境開発が苦手な人の役に立てれば幸いである。

追記

Capistranoでunicornを使ったアプリをデプロイしているとBundler::GemfileNotFoundという例外があがることがある。
というかはまったので追加しました。


ENV['BUNDLE_GEMFILE'] = rails_root + "/Gemfile"