Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

環境

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を試す

まずはWebServerの設定をします

Railsのインストール

次の記事を参考にさせていただき,RubyとRailsを入れました.

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を見るようにする

~/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」のところのコメントを外してください.

~/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は各環境にあったものに書き換えてください.

~/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の起動スクリプトの作成

起動スクリプトは拝借しました.

~/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の動作確認

ちゃんと返ってきてますね.

[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の最新版をインストールする手順

Nginxのバージョン

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

Nginxの設定(Unicornと連携)(WebServer)

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)

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の起動

[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

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

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

larufa
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした