Rails + Unicorn + Nginx でサーバを構築する



#環境
Vagrant (CentOS 6.5)

LoadBalancerのIP: 192.168.33.81 と グローバルIP 
WebServer1のIP: 192.168.33.82
WebServer2のIP: 192.168.33.83

※ 192.168.33.80/24 はプライベートネットワーク

#Vagrantの環境の構築
実はロードバランサ（LVS）を試そうと思っていたので，次の記事を参考にさせていただき，環境を構築しました．

[vagrantのCentOS6.5でLVSを試す](http://qiita.com/ftakao2007/items/79c0e34657e2664801cf "vagrantのCentOS6.5でLVSを試す")




#まずはWebServerの設定をします




#Railsのインストール
次の記事を参考にさせていただき，RubyとRailsを入れました．

[rbenvでRuby2.1.3,Rails4.1.6インストール on CentOS6.5 (Vagrant)](http://qiita.com/icche/items/801ce357d41fd0137b79 "rbenvでRuby2.1.3,Rails4.1.6インストール on CentOS6.5 (Vagrant)")

####Rubyのバージョン

```
[root@vagrant-centos65 ~]$ ruby -v
ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-linux]
```

####Railsのバージョン

```
[root@vagrant-centos65 ~]$ rails -v
Rails 4.1.6
```





#Railsでアプリケーションの作成
次のコマンドでアプリケーションを作成し，コントローラも作成します．

```
[root@vagrant-centos65 ~]$ cd ~
[root@vagrant-centos65 ~]$ rails new testapp
[root@vagrant-centos65 ~]$ rails g controller Tests index
```

次のファイルを編集し，ルート(`http://localhost/`) にアクセスした場合に、indexActionを見るようにする

```ruby:~/testapp/config/routes.rb
Rails.application.routes.draw do
  root :to => 'tests#index'

  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".

  # You can have the root of your site routed with "root"
  
  		：
  		：
  
end
```




#Unicornのインストール
次のファイルの「unicorn」のところのコメントを外してください．

```ruby:~/testapp/Gemfile
source 'https://rubygems.org'


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.6'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer',  platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0',          group: :doc

# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring',        group: :development

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use unicorn as the app server
gem 'unicorn'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

# Use debugger
# gem 'debugger', group: [:development, :test]
```

そしてインストールします．

```
[root@vagrant-centos65 ~]$ cd ~/testapp
[root@vagrant-centos65 ~]$ bundle install
```


#Unicornの設定
/root/testappのrootは各環境にあったものに書き換えてください．

```ruby:~/testapp/config/unicorn.rb
# -*- coding: utf-8 -*-
worker_processes 2

listen  '/tmp/unicorn.sock'
pid     '/tmp/unicorn.pid'

log = '/root/testapp/log/unicorn.log'
stderr_path File.expand_path('log/unicorn.log', '/root/testapp/')
stdout_path File.expand_path('log/unicorn.log', '/root/testapp/')

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

before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

old_pid = "#{ server.config[:pid] }.oldbin"
unless old_pid == server.pid
  begin
   sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
   Process.kill :QUIT, 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
```

#Unicornの起動スクリプトの作成
起動スクリプトは拝借しました．

```bash:~/testapp/script/unicorn
#!/bin/bash

set -e

TIMEOUT=${TIMEOUT-60}
APP_ROOT=${my_app}
PID=/tmp/unicorn.pid
#RAILS_ENV=production
RAILS_ENV=development
CMD="bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb -E $RAILS_ENV"
action="$1"
set -u

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 $action in
start)
    sig 0 && echo >&2 "Already running" && exit 0
    $CMD
    ;;
stop)
    sig QUIT && rm -f ${PID} && 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 '$CMD' instead"
    $CMD
    ;;
upgrade)
    if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
    then
        n=$TIMEOUT
        while test -s $old_pid && test $n -ge 0
        do
            printf '.' && sleep 1 && n=$(( $n - 1 ))
        done
        echo

        if test $n -lt 0 && test -s $old_pid
        then
            echo >&2 "$old_pid still exists after $TIMEOUT seconds"
            exit 1
        fi
        exit 0
    fi
    echo >&2 "Couldn't upgrade, starting '$CMD' instead"
    $CMD
    ;;
reopen-logs)
    sig USR1
    ;;
*)
    echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
    exit 1
    ;;
esac
```






#Unicornの動作確認
ちゃんと返ってきてますね．

```html
[root@vagrant-centos65 ~]# ~/testapp/script/unicorn start
[root@vagrant-centos65 ~]# curl localhost:8080
<!DOCTYPE html>
<html>
<head>
  <title>Testapp</title>
  <link data-turbolinks-track="true" href="/assets/tests.css?body=1" media="all" rel="stylesheet" />
<link data-turbolinks-track="true" href="/assets/application.css?body=1" media="all" rel="stylesheet" />
  <script data-turbolinks-track="true" src="/assets/jquery.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery_ujs.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/turbolinks.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/tests.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/application.js?body=1"></script>
  <meta content="authenticity_token" name="csrf-param" />
<meta content="rc3+bjfvcy2GtRru/GGkV+9CuAxLOFbRVBShmmkeqCM=" name="csrf-token" />
</head>
<body>

<h1>Tests#index</h1>
<p>Find me in app/views/tests/index.html.erb</p>


</body>
</html>
```






#Nginxのインストール
Nginxのインストールは次の記事を参考にさせていただきました．

[CentOS6.xにてnginxの最新版をインストールする手順](http://qiita.com/utano320/items/0c0d9b84a9a28525bcb9 "CentOS6.xにてnginxの最新版をインストールする手順")

####Nginxのバージョン

```
[root@vagrant-centos65 ~]$ nginx -v
nginx version: nginx/1.6.2
```






#Nginxの設定(Unicornと連携)(WebServer)
Nginxのファイルを編集します．

```nginx:/etc/nginx/conf.d/rails-app.conf
upstream rails-unicorn {
    server unix:/tmp/unicorn.sock;
}

server {
    listen       80;
    server_name  localhost;

    access_log  /var/log/nginx/log/host.access.log  main;

    root /root/testapp/public;
    try_files $uri $uri.html $uri/index.html @rails-unicorn;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /root/testapp/public;
    }
    #error_page  404              /404.html;

    location ~ ^/assets/(.*) {
        alias /root/testapp/public/assets/$1;
    }

    location @rails-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://rails-unicorn;
    }

}
```






#Nginxの起動

```
[root@vagrant-centos65 ~]$ nginx
[root@vagrant-centos65 ~]# curl localhost
<!DOCTYPE html>
<html>
<head>
  <title>Testapp</title>
  <link data-turbolinks-track="true" href="/assets/tests.css?body=1" media="all" rel="stylesheet" />
<link data-turbolinks-track="true" href="/assets/application.css?body=1" media="all" rel="stylesheet" />
  <script data-turbolinks-track="true" src="/assets/jquery.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery_ujs.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/turbolinks.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/tests.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/application.js?body=1"></script>
  <meta content="authenticity_token" name="csrf-param" />
<meta content="WwNbfm70aA5AyUbNzR19WHEDagc6HkVWWW7oo0ozyFA=" name="csrf-token" />
</head>
<body>

<h1>Tests#index</h1>
<p>Find me in app/views/tests/index.html.erb</p>


</body>
</html>
```


#ここからLoadBalancerの設定です
同様にLoadBalancerにもNginxをインストールします．
Nginxをロードバランサとして使います．



#Nginxの設定(LoadBalancer)

```nginx
ginx:/etc/nginx/nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
    server_tokens off;

	# ここにバックエンドのサーバのIPを追加
	# デフォルトだとラウンドロビンです
    upstream webserver {
        server 192.168.33.82;
        server 192.168.33.83;
    }

}
```

#Nginxの起動

```bash
[root@vagrant-centos65 ~]$ nginx
```

#WebServerのデフォルトゲートウェイの設定
LoadBalancerの内側アドレスをデフォルトゲートウェイにする必要があります．

```
[root@vagrant-centos65 ~]$ route add default gw 192.168.33.81
[root@vagrant-centos65 ~]$ route del -net default gw 10.0.2.2 dev eth0
```

ただし，この設定をすると，WebServerが外部と通信できなくなってしまいます．（現状のVagrant環境では）

ですので，yum等で何かをインストールする時は，戻してあげてください．

```
[root@vagrant-centos65 ~]$ route add default gw 10.0.2.2
[root@vagrant-centos65 ~]$ route del -net default gw 192.168.33.81 dev eth1
```

※この通信できなくなってしまうのを，NATでなんとかできそうな気もするのですが，現状の私では設定できませんでした．

#動作確認
ブラウザでLoadBalancerに設定してあるグローバルIPにアクセスします．
次のものが確認できればOKです．
![スクリーンショット 2015-03-04 19.07.31.png](https://qiita-image-store.s3.amazonaws.com/0/63019/659e3e34-05c5-b96b-fb35-47d1ee17addd.png "スクリーンショット 2015-03-04 19.07.31.png")

同じ内容だと振り分けられているかがわかりにくいので，/root/testapp/app/views/tests/index.html.erb にWebServer1といった目印を追加してあげるといいと思います．


#その他参考にさせていただいた記事

* [nginx + unicorn + Railsの設定方法](http://qiita.com/akito1986/items/56198edcafc222b320a8 "nginx + unicorn + Railsの設定方法")
* [rails + nginx + unicorn連携](http://qiita.com/shinyashikis@github/items/ace49154f0c71c65b2c9 "rails + nginx + unicorn連携")
* [Vagrant(CentOS6.5)にRails4.1 + Nginx + Unicorn + MySQL環境でRailsを起動する。](http://qiita.com/teitei_tk/items/74794983d9893c3e7a05 "Vagrant(CentOS6.5)にRails4.1 + Nginx + Unicorn + MySQL環境でRailsを起動する。")
* [vagrantのCentOS6.5でLVSを試す](http://qiita.com/ftakao2007/items/79c0e34657e2664801cf "vagrantのCentOS6.5でLVSを試す")