Unicorn設定のまとめ

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

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

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

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

```ruby:Gemfile
gem 'unicorn'
```

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

参考：
[Rails4.2 を Nginx + Unicorn で動作させる](http://jetglass.hatenablog.jp/entry/2015/06/26/205256)

```ruby: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`で以下のコマンドを叩きます。

```sh
$ bundle exec unicorn_rails -c config/unicorn.rb
```

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

```sh
$ bundle exec unicorn -c config/unicorn.rb
```

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

細かい点で挙動に違いがあります。
以下のURLが参考になると思います。
[unicornとunicorn_railsのオプションの違い](http://unlearned.hatenablog.com/entry/2014/02/28/015554)

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

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

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

```
http://localhost:8080
```

## Unicornの停止/再起動
[こちら](http://tachesimazzoca.github.io/wiki/rails3/unicorn.html)のサイト通りです。

以下、転記します。

### 停止コマンド

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

### 再起動コマンド

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

### 緩やかな再起動コマンド

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

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

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

## CapistranoでUnicornを使う場合
別記事でまとめる予定だが、以下の`gem`を使用すると簡単に使える。

```ruby:Gemfile
gem 'capistrano3-unicorn'
```

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

```ruby:Capfile
require 'capistrano3/unicorn'
```

[中身](https://github.com/tablexi/capistrano3-unicorn/blob/master/lib/capistrano3/tasks/unicorn.rake)を見ればわかるが、これは自分自身でも作る事ができる。
また、起動コマンドが`unicorn`になってるので注意が必要である。

### 僕が犯したミス
僕は`capistrano3/unicorn`が何ものかわからなかったため、`require 'capistrano3/unicorn'`と`unicorn.rake`を両方書いてしまい、二重に`unicorn`が立ち上がってしまうという恥ずかしいミスをしてしまった・・・。
しかも、中身を追わなかったため原因の解明にとても時間がかかった・・・。
（ちゃんと[中身](https://github.com/tablexi/capistrano3-unicorn/blob/master/lib/capistrano3/tasks/unicorn.rake)は見るべきですね。）

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

### Railsのログローテーションについて
こちらが参考になります。
[Ruby on Rails - Unicorn のログローテーション！](http://www.mk-mode.com/octopress/2014/02/02/unicorn-logrotation/)

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

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


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

```rb

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