Shred IT!!!!

IT全般について試したこと・勉強したことを綴ったり、趣味について語るブログ

Rails4.2 を Nginx + Unicorn で動作させる

概要


Rails や Padrino の案件に関わってきたが、全て Apache + Passenger の構成で動作させていた。
最近では、Nginx + Unicorn で動作させているという話しをよく聞くので、環境作りを試してみる。

前提


  • Rails4.2 をインストール済み
  • bundler を使っている

Unicorn のインストール


Gemfile に下記を追加。

# vim Gemfile
gem 'unicorn'

下記を実行し、インストール。

# bundle install

Nginx のインストール


下記は mac で HomeBrew 使った場合。
環境によって yum なり aptitude なり使い分ける。

# brew install nginx

Unicorn の設定


config/unicorn.rb を新規作成

Unicorn の設定ファイルを必要最低限の内容で新規作成。

# vim config/unicorn.rb
rails_root = File.expand_path('../../', __FILE__)
rails_env = ENV['RAILS_ENV'] || "development"

worker_processes 2
working_directory rails_root

#listen "#{rails_root}/tmp/#{rails_env}_unicorn.sock"
listen 8080
pid "#{rails_root}/tmp/#{rails_env}_unicorn.pid"

stderr_path "#{rails_root}/log/#{rails_env}_unicorn_error.log"
stdout_path "#{rails_root}/log/#{rails_env}_unicorn.log"

一旦、この最低限の設定で Unicorn 単体で動作してみる。
わざわざ RAILS.env の値をファイル名に利用するようにしてみた。
動かすだけなら無駄だった・・・

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

下記にアクセスできることや、pid ファイル、log ファイルが作成されていることを確認する。

http://localhost:8080
config/unicorn.rb を編集

Nginx と連携するために少し修正。

# vim config/unicorn.rb
...
listen "#{rails_root}/tmp/#{rails_env}_unicorn.sock"
#listen 8080
...

Nginx と Unicorn の通信に Unix Domain Socket を利用してみる。
ざっくり説明すると、Nginx + Unicorn を一つのサーバ内で構築する場合、 つまり、ネットワーク越しに通信しない場合は Unix Domain Socket を利用した方が速いようだ。

詳細は下記。
nginx - 調べなきゃ寝れない!と調べたら余計に寝れなくなったソケットの話 - Qiita

Unicorn 再起動

起動させていたのをctrl-cで止めて、下記実行。

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

ちなみに-Dを付けると、バックグラウンドで実行される。
その場合、止めるときはプロセスIDを探してkillする。

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

Nginx の設定


nginx.conf へ追記

macbrew を使ってインストールした場合、 下記に設定ファイルがあるので開いて編集。

# vim /usr/local/etc/nginx/nginx.conf

http { ブロック内に下記を追加する。
元から書かれているserver {ブロックは削除またはコメントアウトすること。

http {
...
    upstream unicorn {
        # unicorn.rbで設定したunicorn.sockを指定
        server unix:{RAILS_ROOT}/tmp/development_unicorn.sock;
    }

    server {
        listen 8080;
        server_name first_app;
        root {RAILS_ROOT}/public;
        access_log {LOG_PATH}/first_app_access.log;
        error_log {LOG_PATH}/first_app_error.log;
        try_files $uri/index.html $uri @unicorn;
        location @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://unicorn;
        }
    }
...
nginx の起動
# nginx

で起動する。

再起動は下記。

# nginx -s reload

下記にアクセスできることを確認する。

http://localhost:8080

nginx 用のログファイルにログが書かれていることを確認できれば終わり。

ホットデプロイの仕組み


Unicorn は下記サイトで説明された仕組みでホットデプロイを実現させるようだ。
unicornのpreload_app - motsatのブログ

Unicorn のプロセス A が Nginx とやり取りしてサイトが動いているとして、 SIGUSR2 を プロセス A に送ると、新しいRails環境を読み込んだプロセス B が誕生する。
プロセス A を終了させることで、Nginx とやり取りするのがプロセス B のみになり、ダウンタイムを発生させないで、アプリのリロードが行える。

コマンドライン上から再現できそうなのでやってみる。

Unicorn の設定編集

Unicorn の起動を止めて、設定ファイルを編集、下記を追加。

# vim config/unicorn.rb
preload_app true
# SIGUSR2 を送ってRails環境を新しく読み込ませるために必要なオプション
コマンドラインで再現する
# 起動中の Unicorn のプロセスIDを確認
# ps aux | grep unicorn
tsuyaxchi         93067   0.1  0.0  2424588    408 s011  R+    9:05PM   0:00.00 grep unicorn
tsuyaxchi         92788   0.0  0.4  2576308  36896 s005  S+    8:19PM   0:04.75 unicorn_rails worker[1] -c config/unicorn.rb -E development
tsuyaxchi         92787   0.0  0.9  2572288  74912 s005  S+    8:19PM   0:04.11 unicorn_rails worker[0] -c config/unicorn.rb -E development
tsuyaxchi         92786   0.0  0.0  2481504   3700 s005  S+    8:19PM   0:00.75 unicorn_rails master -c config/unicorn.rb -E development

# マスタに対して SIGUSR2 を送る
# kill -s USR2 92786

# プロセスを確認する
# 92786 には master (old) と追記されている
# 93092 には新しい master が誕生している
# ps aux | grep unicorn
tsuyaxchi         92788   0.0  0.0  2576308   3916 s005  S+    8:19PM   0:04.80 unicorn_rails worker[1] -c config/unicorn.rb -E development
tsuyaxchi         92787   0.0  0.0  2579392   3844 s005  S+    8:19PM   0:04.58 unicorn_rails worker[0] -c config/unicorn.rb -E development
tsuyaxchi         92786   0.0  0.1  2481504   4400 s005  S+    8:19PM   0:00.75 unicorn_rails master (old) -c config/unicorn.rb -E development
tsuyaxchi         93104   0.0  0.0  2423368    204 s011  R+    9:10PM   0:00.00 grep unicorn
tsuyaxchi         93100   0.0  0.1  2562604   7056 s005  S+    9:10PM   0:00.01 unicorn_rails worker[1] -c config/unicorn.rb -E development
tsuyaxchi         93099   0.0  0.1  2562604   7920 s005  S+    9:10PM   0:00.01 unicorn_rails worker[0] -c config/unicorn.rb -E development
tsuyaxchi         93092   0.0  1.2  2562604  99352 s005  S+    9:10PM   0:03.32 unicorn_rails master -c config/unicorn.rb -E development

# master(old) を終了させる
# kill -s QUIT 92786

# ps aux | grep unicorn
tsuyaxchi         93113   0.0  0.0  2432784    620 s011  S+    9:12PM   0:00.00 grep unicorn
tsuyaxchi         93100   0.0  1.0  2565808  84140 s005  S     9:10PM   0:00.54 unicorn_rails worker[1] -c config/unicorn.rb -E development
tsuyaxchi         93099   0.0  0.9  2577340  76700 s005  S     9:10PM   0:01.04 unicorn_rails worker[0] -c config/unicorn.rb -E development
tsuyaxchi         93092   0.0  0.4  2562604  32184 s005  S     9:10PM   0:03.32 unicorn_rails master -c config/unicorn.rb -E development

下記に問題なくアクセスできることを確認。

http://localhost:8080

まとめ


動作させるだけなら、非常に簡単。
ここから、パフォーマンスが出る設定値を探して行くのが、 楽しいところであり難しいところ。

あと、Unicornホットデプロイできる仕組みを持っているようだ。

Capistrano + Unicornホットデプロイする仕組みを知っておきたいので、 今度やろうと思う。

Unicornのダウンタイムなし再起動は考え無しに使うと危険 | ひげろぐ

RailsのデプロイとUnicornのトラブルシューティング | KRAY Inc

参考


Nginx+UnicornでRailsを動かすon Mac - Qiita

rails4 + unicorn + nginx - Qiita