maehachi08 Anything Blog

2012年10月28日
CentOS6.3でNginx + Unicorn + Rails

近々、VPSを移行しようと思うのですが、Apache + PassengerからNginx + Unicornに変更します!ついでに、Rubyをrbenvでバージョン管理します。
出来るだけ、構築中のエラーへの対処方法なども含めて載せますが、Rubyの再コンパイルとかもやったので、そのあたりはRubyコンパイルを一度で済むように説明します。

rbenvインストール

rubyバージョン管理にはrbenv(アール・ビー・エンブ) + ruby-build + rbenv-gemsetを使用します。rvmの方が高機能だといわれていますが、どうせ使いこなせないし、rvmはmvとかcpとかのバイナリを置き換えてしまうという暴挙に出るので使ってません。rbenvのインストールは、通常、~/.rbenvといったユーザ環境ごとにインストールするケースが多いようですが、システム全体で使いたいので/usr/localディレクトリ以下にインストールします。
rbenvはgithub上で公開されています。githubからダウンロードするにはgit cloneコマンドを使いますが、gitコマンドがインストールされていない場合は以下2コマンドを叩くとインストールできます。ちなみに、gitのRPMパッケージはCentOSオリジナルレポジトリに存在しないのでrpmforgeを使いました。

rpm -ivh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-1.el6.rf.x86_64.rpm
yum -y install git

rbenvをインストールします。githubのURLの後ろにパスを指定することで指定したパスにインストールすることが出来ます。

git clone git://github.com/sstephenson/rbenv.git /usr/local/rbenv

ディレクトリを作成します。

mkdir /usr/local/rbenv/{shims,plugins,versions}

rbenv-gemsetをインストールします。

git clone git://github.com/jamis/rbenv-gemset.git /usr/local/rbenv/plugins/gemset

ruby-buildをインストールします。ruby-buildをインストールすることでrbenv installコマンドが使えるようになります。

git clone git://github.com/sstephenson/ruby-build.git /usr/local/ruby-build

cd /usr/local/ruby-build
./install.sh

rbenvコマンドのパスをPATH環境変数に追加します。ユーザ単位であれば(bashならば)~/.bash_profileとかに追記しますが、システム全体で設定を反映させたいので、/etc/profile.d/rbenv.shを作成し、シェル起動毎に読み込むようにします。

cat << EOT > /etc/profile.d/rbenv.sh
export RBENV_ROOT="/usr/local/rbenv"
export PATH="/usr/local/rbenv/bin:$PATH"
eval "\$(rbenv init -)"
EOT

今、起動中のシェルに反映させたいので、手動実行します。

source /etc/profile.d/rbenv.sh

これでrbenvコマンドが使えるようになりました。

rubyインストール(準備編)

構築を通して、ruby実行時にいくつかエラーが出て、不足ライブラリをインストールしました。rubyインストール前にこのあたりを説明します。
"gem install rails"実行で以下エラーが出ました。

# gem install rails
ERROR:  Loading command: install (LoadError)
    cannot load such file -- zlib
ERROR:  While executing gem ... (NameError)
    uninitialized constant Gem::Commands::InstallCommand

対応として、zlib関連パッケージを先に入れておきます。

yum -y install zlib*

"rails new test_app -d mysql"実行で以下エラーが出ました。

Fetching gem metadata from https://rubygems.org/.
Could not load OpenSSL.
You must recompile Ruby with OpenSSL support or change the sources in your
Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL
using RVM are available at rvm.io/packages/openssl.

そこでRubyの拡張ライブラリを実行して不足ライブラリをチェックします。

find / -name "extconf.rb" | grep ssl
/tmp/ruby-build.20121025173049.25590/ruby-1.9.3-p286/ext/openssl/extconf.rb
ruby /tmp/ruby-build.20121025173049.25590/ruby-1.9.3-p286/ext/openssl/extconf.rb
=== OpenSSL for Ruby configurator ===
=== Checking for system dependent stuff... ===
checking for t_open() in -lnsl... no
checking for socket() in -lsocket... no
checking for assert.h... yes
=== Checking for required stuff... ===
checking for openssl/ssl.h... no
=== Checking for required stuff failed. ===
Makefile wasn't created. Fix the errors above.
*** /tmp/ruby-build.20121025173049.25590/ruby-1.9.3-p286/ext/openssl/extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

不足するライブラリが判明しました。

checking for openssl/ssl.h... no

opensslのdevelパッケージをインストールします。

yum -y install openssl-devel

rubyインストール(実行編)

rbenv installコマンドでインストール可能なrubyのバージョンを確認するには-lオプションを付けて実行します。

rbenv install -l
1.9.3-dev
1.9.3-p0
1.9.3-p125
1.9.3-p194
1.9.3-p286
1.9.3-preview1
1.9.3-rc1
2.0.0-dev

今回は1.9.3-p286をインストールします。インストール環境によっては30分程度かかります。

rbenv install 1.9.3-p286 /usr/local/rbenv/versions/ruby-1.9.3-p286

システムで使うrubyをrbenvでインストールしたrubyバージョンに設定したいので、以下コマンドを実行します。

rbenv global 1.9.3-p286

MySQLインストール

mysql5.5系をRPMで入れたいので、remiレポジトリ用のrepoファイルを定義します。remi-release-6.rpmパッケージはepel-release-6-7.noarch.rpmに依存するので先にepelを入れます。

rpm -ivh http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/x86_64/epel-release-6-7.noarch.rpm
rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

作成された/etc/yum.repos.d/remi.repoをenable=1に変更します。

sed -i.ogiginal -e 's/enabled=0/enabled=1/' /etc/yum.repos.d/remi.repo

mysqlパッケージ群をインストールします。CentOSオリジナルのmysqlがインストール済みの場合は削除してからの方がいいかもしれませんが、依存関係でmysql-libsの削除が難しい場合は、そのまま実行してもupdateされると思います。

yum -y install mysql mysql-libs mysql-devel mysql-server

my.cnfを持ってきます。

cp -af /usr/share/mysql/my-medium.cnf /etc/my.cnf

サービス自動起動設定を行います。mysqlサービスを起動したらmysqlデータベースが初期化されます。

chkconfig mysqld on
service mysqld start

動作確認です。

mysql -u root -e 'select user,host from mysql.user'

Nginxのインストール

NginxはEPELなのでEPELレポジトリ用のrepoファイルを定義します。今回はremiレポジトリを定義する過程でEPELレポジトリの設定もしていますので下記コマンドの実行は不要です。

rpm -ivh http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/x86_64/epel-release-6-7.noarch.rpm

2012年10月25日時点でのepelでのnginxバージョンは1.0.15です。

yum info nginx
Name        : nginx
Arch        : x86_64
Version     : 1.0.15
Release     : 2.el6
Size        : 376 k
Repo        : epel
Summary     : A high performance web server and reverse proxy server
URL         : http://nginx.org/
License     : BSD
Description : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
            : IMAP protocols, with a strong focus on high concurrency, performance and low
            : memory usage.
yum -y install nginx

nginxインストールによって作成されたディレクトリ、ファイルの一覧を確認したい場合は、以下のコマンドで一発です。

rpm -ql nginx
/etc/logrotate.d/nginx
/etc/nginx
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
/etc/nginx/conf.d/ssl.conf
/etc/nginx/conf.d/virtual.conf
/etc/nginx/fastcgi.conf
/etc/nginx/fastcgi.conf.default
/etc/nginx/fastcgi_params
/etc/nginx/fastcgi_params.default
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/mime.types.default
/etc/nginx/nginx.conf
/etc/nginx/nginx.conf.default
/etc/nginx/scgi_params
/etc/nginx/scgi_params.default
/etc/nginx/uwsgi_params
/etc/nginx/uwsgi_params.default
/etc/nginx/win-utf
/etc/rc.d/init.d/nginx
/etc/sysconfig/nginx
/usr/lib64/perl5/vendor_perl/auto/nginx
/usr/lib64/perl5/vendor_perl/auto/nginx/nginx.so
/usr/lib64/perl5/vendor_perl/nginx.pm
/usr/sbin/nginx
/usr/share/doc/nginx-1.0.15
/usr/share/doc/nginx-1.0.15/CHANGES
/usr/share/doc/nginx-1.0.15/LICENSE
/usr/share/doc/nginx-1.0.15/README
/usr/share/man/man3/nginx.3pm.gz
/usr/share/nginx
/usr/share/nginx/html
/usr/share/nginx/html/404.html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html
/usr/share/nginx/html/nginx-logo.png
/usr/share/nginx/html/poweredby.png
/var/lib/nginx
/var/lib/nginx/tmp
/var/log/nginx

nginxサービスの自動起動を設定します。

chkconfig nginx on
service nginx start

これでサーバIPアドレスにアクセスすることでNginxデフォルトページが表示されました。

railsインストール

railsインストールはgemコマンド一発です。

gem install rails
# rails -v
Rails 3.2.8

railsアプリケーションの作成

mkdir -p /var/www/rails
cd /var/www/rails
rails new test_app -d mysql

unicornインストール

unicornはシェル上で"gem install unicorn"としてもインストールできますが、rails3では各アプリケーションごとにGemfileで定義する方法が正しいと思います。ついでに"rake db:create"コマンド実行時に足らないとエラーでるので、execjsとtherubyracerも入れます。

cd test_app/
cp -p Gemfile Gemfile.bak
vim Gemfile

修正箇所をdiffで確認します。

# diff -u Gemfile.bak Gemfile
--- Gemfile.bak 2012-10-27 00:37:43.348772124 +0900
+++ Gemfile     2012-10-27 15:36:55.749034003 +0900
-  # gem 'therubyracer', :platforms => :ruby
+
+gem 'execjs'
+gem 'therubyracer', :platforms => :ruby
-# gem 'unicorn'
+gem 'unicorn'
bundle install

unicorn_railsコマンド(/usr/local/rbenv/versions/1.9.3-p286/bin/unicorn_rails)を読み込むために/etc/profile.d/rbenv.shを読み込みます。

source /etc/profile.d/rbenv.sh

Nginx設定

RPMパッケージからNginxをインストールした場合のnginx.confは/etc/nginx/nginx.confになります。sampleのnginx.confがgithubで公開されていますのでwgetで落としてきて必要箇所を修正します。

cd /etc/nginx
mv nginx.conf nginx.conf.original
wget https://raw.github.com/defunkt/unicorn/master/examples/nginx.conf
cp -a nginx.conf nginx.conf.old
vim nginx.conf

修正箇所をdiffした結果です。

--- /etc/nginx/nginx.conf.old   2012-10-28 09:48:55.689246097 +0900
+++ /etc/nginx/nginx.conf       2012-10-28 16:18:29.959591990 +0900
@@ -20,12 +20,12 @@
-user nobody nogroup; # for systems with a "nogroup"
+user nginx nginx; # for systems with a "nogroup"
-pid /tmp/nginx.pid;
-error_log /tmp/nginx.error.log;
+pid /var/run/nginx.pid;
+error_log /var/log/nginx/nginx.error.log;
@@ -42,7 +42,7 @@
-  access_log /tmp/nginx.access.log combined;
+  access_log /var/log/nginx/nginx.access.log combined;
@@ -74,7 +74,7 @@
-    server unix:/tmp/.sock fail_timeout=0;
+    server unix:/tmp/nginx.sock fail_timeout=0;
@@ -84,7 +84,7 @@
-    # listen 80 default deferred; # for Linux
+     listen 80 default deferred; # for Linux
@@ -104,7 +104,7 @@
-    root /path/to/app/current/public;
+    root /var/www/rails/test_app/public;
@@ -150,7 +150,7 @@
-      root /path/to/app/current/public;
+      root /var/www/rails/test_app/public;

Railsアプリにunicorn用のconfファイル"unicorn.rb"を作成

/var/www/rails/test_app/unicorn.rbを作成します。sampleのunicorn.rbがgithubで公開されてますのでwgetで落としてから必要箇所を修正します。

cd /var/www/rails/test_app/config/
wget -O unicorn.rb https://raw.github.com/defunkt/unicorn/master/examples/unicorn.conf.rb
vim unicorn.rb

修正箇所をdiffした結果です。

--- unicorn.rb.old      2012-10-28 16:25:04.663584070 +0900
+++ unicorn.rb  2012-10-28 16:24:13.705514840 +0900
@@ -8,6 +8,8 @@
+rails_env = ENV['RAILS_ENV'] || 'production'
+
@@ -21,24 +23,24 @@
-working_directory "/path/to/app/current" # available in 0.94.0+
+working_directory "/var/www/rails/test_app" # available in 0.94.0+
-listen "/tmp/.sock", :backlog => 64
+listen "/tmp/nginx.sock", :backlog => 64
-pid "/path/to/app/shared/pids/unicorn.pid"
+pid "/var/www/rails/test_app/config/shared/pids/unicorn.pid"
-stderr_path "/path/to/app/shared/log/unicorn.stderr.log"
-stdout_path "/path/to/app/shared/log/unicorn.stdout.log"
+stderr_path "/var/www/rails/test_app/config/shared/log/unicorn.stderr.log"
+stdout_path "/var/www/rails/test_app/config/shared/log/unicorn.stdout.log"

unicornで必要なディレクトリを作成します。

mkdir -p config/shared/{pids,log}

アプリ用データベース/コントローラ作成

rakeコマンド一発です。エラーがでる場合はconfig/database.ymlファイルの設定確認、及び必要なgemモジュールを確認しましょう。

rake db:create

helloコントローラーを作成します。一緒にindexアクションを指定することでapp/views/hello/index.html.erbも作成してくれますー。

rails g controller hello index

public/index.htmlを削除しないとルートへのアクセスがこいつになってしまうので削除します。

rf -f public/index.html

ルーティング設定のコメントアウト2箇所をコメント外します。

cp -p config/routes.rb config/routes.rb.original
vim config/routes.rb

修正箇所をdiffした結果です。

--- config/routes.rb.original   2012-10-28 17:52:48.268251232 +0900
+++ config/routes.rb    2012-10-28 16:31:24.913231444 +0900
@@ -50,11 +50,11 @@
-  # root :to => 'hello#index'
+   root :to => 'hello#index'
-  # match ':controller(/:action(/:id))(.:format)'
+   match ':controller(/:action(/:id))(.:format)'

unicorn起動スクリプトの作成・登録

unicornを手動起動させる場合は以下コマンドです。

unicorn_rails -c /var/www/rails/test_app/config/unicorn.rb -D

でも、サーバ起動毎にコレ実行したくないですよね。起動スクリプトを作成してサービス自動起動に設定しましょう。

vim /etc/init.d/unicorn_rails_test_app
#!/bin/bash
#
# unicorn_rails_redmine Startup script for unicorn.
#
# chkconfig: - 86 15
# description: redmine on unicorn start/stop script.
#

#
# set rvm environment valiables.
#
export PATH=/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/rbenv/versions/1.9.3-p286/bin
export MY_RUBY_HOME=/usr/local/rbenv/versions/1.9.3-p286

set -u
set -e

APP_NAME=test_app
APP_ROOT="/var/www/rails/$APP_NAME"
CNF="$APP_ROOT/config/unicorn.rb"
PID="$APP_ROOT/config/shared/pids/unicorn.pid"
ENV=production

UNICORN_OPTS="-D -E $ENV -c $CNF"

old_pid="$PID.oldbin"

cd $APP_ROOT || exit 1

sig () {
        test -s "$PID" && kill -$1 `cat $PID`
}

oldsig () {
        test -s $old_pid && kill -$1 `cat $old_pid`
}

case ${1-help} in
start)
        sig 0 && echo >&2 "Already running" && exit 0
        cd $APP_ROOT ; unicorn_rails $UNICORN_OPTS
        ;;
stop)
        sig QUIT && exit 0
        echo >&2 "Not running"
        ;;
force-stop)
        sig TERM && exit 0
        echo >&2 "Not running"
        ;;
restart|reload)
        sig HUP && echo reloaded OK && exit 0
        echo >&2 "Couldn't reload, starting instead"
        unicorn_rails $UNICORN_OPTS
        ;;
upgrade)
        sig USR2 && exit 0
        echo >&2 "Couldn't upgrade, starting instead"
        unicorn_rails $UNICORN_OPTS
        ;;
rotate)
        sig USR1 && echo rotated logs OK && exit 0
        echo >&2 "Couldn't rotate logs" && exit 1
        ;;
*)
        echo >&2 "Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
        exit 1
        ;;
esac

起動スクリプトに実行権限を与えます。

chmod 755 /etc/init.d/unicorn_rails_test_app

自動起動を設定します。

chkconfig --add unicorn_rails_test_app
chkconfig unicorn_rails_test_app on
chkconfig --list | grep unicorn_rails_test_app
unicorn_rails_test_app  0:off   1:off   2:on    3:on    4:on    5:on    6:off

これでサーバ起動時にinitから起動スクリプトが読み込まれます。
unicornを起動してみます。

service unicorn_rails_test_app start

nginx再起動

service nginx restart

http://にアクセスしてみてください。
hello#indexが表示されましたでしょうか。