2013/10/01

Redmine を Nginx + Unicorn で動かす

前回までのあらすじ


Nginx を Apache のリバースプロキシに設定した。

今日の目標

現在 Apache + Passenger で動いている Rails アプリの Redmine を Nginx + Unicorn に切り替えてみよう。
Redmine は /var/www/redmine に設置されている。

Gem の追加

Redmine の gem に unicorn を追加する。
もしRedmine本体は使用しないgem(例: mongrel, fcgi)もロードしたい場合、 Gemfile.local というファイルをRedmineのディレクトリに作成してください。
Redmineのインストール — Redmine Guide 日本語訳

ということなので Gemfile.local を作成した。
# Gemfile.local
gem "unicorn"

インストール。
$ bundle install

Unicorn の設定

Redmine の config ディレクトリに unicorn.rb というファイルを作成した。

worker_processes 1

timeout 60

listen File.expand_path("tmp/sockets/unicorn.sock", ENV['RAILS_ROOT'])

pid File.expand_path("tmp/pids/unicorn.pid", ENV['RAILS_ROOT'])

stdout_path File.expand_path("log/unicorn.stdout.log", ENV['RAILS_ROOT'])
stderr_path File.expand_path("log/unicorn.stderr.log", ENV['RAILS_ROOT'])

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

before_fork do |server, worker|
# この設定はpreload_app trueの場合に必須
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

# USR2シグナルで旧プロセスを終了させる
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|
# この設定はpreload_app trueの場合に必須
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

とりあえず socket のパス。これ大事。
tmp/sockets/unicorn.sock

pid のパス。これも大事。
tmp/pids/unicorn.pid

Unicorn 起動


え、Unicorn て Apache とか Nginx とかとは別口で起動しておかないといけないの?
後で自動化できないか調べなきゃ。
$ bundle exec unicorn_rails -c config/unicorn.rb -D -E production

コマンドのオプションは -c で設定ファイル指定、-E で動作モード指定、-D がデーモン化。
終了の仕方は力ずく。
$ kill -quit 'cat /var/www/redmine/tmp/pids/unicorn.pid'

Nginx の設定


/etc/nginx/sites-available/ に設定ファイルを作成して /etc/nginx/sites-enabled/ からリンクを張る。
upstream redmine {
server unix:/var/www/redmine/tmp/sockets/unicorn.sock;
}

server {
listen 80;
server_name redmine.tepidworks.jp;

location / {
root /var/www/redmine/public;

if ( -f $request_filename ) { break; }

proxy_set_header X-Real-IP  $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://redmine;
}
}

if ( -f $request_filename ) { break; } があるので、静的ファイルへのアクセスは Rails を通さないで Nginx が直接返す。*1

Nginx 再起動

$ sudo service nginx restart

無事アクセスできた。

*1:少なくとも、確認した限り静的ファイルへのアクセスでは Rails がログを吐かなかったので Unicorn に処理は渡っていないはず。


2013/09/30

Apache のリバースプロキシとして Nginx を導入する

参考

NginxとApache - Qiita [キータ]

環境

Debian 7.1
Apache 2.2.22
Nginx 1.2.1

Nginx

Rails 関連の情報を漁っていて、前々から「Nginx + Unicorn が良いらしい」と聞いていたので興味はあったのだが、Nginx については「Apache より軽量な HTTP サーバー」程度の認識しかなかった。
ところが今さらながらに Nginx と Apache の共存が可能と知り、「Nginx + Unicorn + Rails」な環境に向けて、ひとまず Apache のリバースプロキシとして Nginx を導入することにした。

実は再挑戦だった

基本的に参考サイトの見よう見まねでの作業となったが、改めてサーバーの環境を確認したところ、Nginx はなぜかインストール済み。
そういえば半年ほど前に入れるだけ入れて良くわからないまま放置していたのだった。
その時に変な風に設定をいじっていたら嫌だなあと思いつつ、面倒くさいので再インストールはしなかったが、結果的に問題はなかったので良しとしておこう。

mod_rpaf

良く分からないのが mod_rpaf だが、どうやら Nginx が受けたリクエストを Apache に渡す時点で、Apache から見ると全部 localhost からのアクセスに見えてしまって実際のアクセス元が分からなくなってしまう問題への対処として必要らしい。
apt で一発。apache のモジュール設定の変更から再起動までやってくれた。素晴らしい。
# aptitude install libapache2-mod-rpaf 

Nginx の設定

Nginx がポート 80 で受けたリクエストを 8000 へリダイレクトさせるための設定ファイルを /etc/nginx/sites-available/ に作成して /etc/nginx/sites-enabled/ からリンクを張った。
/etc/nginx/sites-available/default へのリンクは使わないので削除。
このあたりの構成は debian 系ユーザであれば apache の設定と同じなので馴染みやすいと思う。
a2ensitea2dissite に相当するコマンドがあればなお良かったが贅沢は言うまい。

apache の設定

/etc/apache2/sites-available/ にある VirtualHost 別の設定ファイルのポートをすべて 8000 に変更、/etc/apache2/ports.conf の NameVirtualHost を *:8000 に、Listen を localhost:8000 に変更した。
Listen の設定で localhost を指定したのは、外部からのポート 8000 へのアクセスを弾くためだ。

再起動

Nginx と Apache を再起動して、無事にアクセスできることを確認。
めでたしめでたし。

2013/09/17

gem: Spring

Rails Application Preloader

そもそもプリローダとは何ぞやと問えば、Rails アプリを事前にロードしておくことで rails rake コマンドを高速化するためのものだ。Spring の他には Zeus や Spork がある。
Spork は少しだけ使っていたことがあるが、事前の設定やら再起動が面倒で個人的にはあまり使い勝手がよろしくなかった。Zeus は知らない。
Spring は gem をインストールするだけで設定などは不要とのこと。
ただし、git のブランチを移動した場合などは再起動のため一度停止しなければならない。まあそれは当たり前か。
$ spring stop

Gemfile に書きたかったら書けばいいじゃない

Install the spring gem. You can add it to your Gemfile if you like but it's optional. You now have a spring command. Don't use it with bundle exec or it will be extremely slow.
Readme - Usage

要は「bundle exec と一緒に使うとめっちゃ遅くなるからやめとけ」とのことらしいので、素直に gem install でインストール。rbenv 環境なので rbenv rehash も忘れずに。

試してみた

まず一度停止。
$ spring stop
Spring stopped.

実行。
$ time spring rake spec
略)
spring rake spec  0.11s user 0.02s system 2% cpu 4.554 total

もういっちょ。
$ time spring rake spec
略)
spring rake spec  0.11s user 0.03s system 5% cpu 2.775 total

確かに速くはなっているのだが、まだクラスもテストケースも全然少ないせいか期待していたほどではないな……。

他にも試してみた

2回目以降の rails c が一瞬で起動する。すげえ。Spring 最高。