うまとま君の技術めも

2015年新卒入社した社畜の勉強内容などなど

Nginx, Unicornで作るRailsアプリ

環境

Railsアプリ

Railsはインストール済みとする。

とりあえず適当にプロジェクトの作成

$ rails new blog

nginxのインストール

aptでnginxの公式リポジトリを使うように設定する。

$ sudo vi /etc/apt/sources.list.d/nginx.list

nginx.listに下記を追記

deb http://nginx.org/packages/ubuntu/ precise nginx
deb-src http://nginx.org/packages/ubuntu/ precise nginx

PGP公開鍵を追加する必要があるらしい

$ curl http://nginx.org/keys/nginx_signing.key | sudo apt-key add -

インストール可能なバージョンを確認

$ sudo apt-get update
$ apt-cache show nginx | grep Version
Version: 1.4.7-1~precise  ## 最新のバージョンが確認できればおk
Version: 1.1.19-1ubuntu0.6
Version: 1.1.19-1ubuntu0.5
Version: 1.1.19-1

nginxのインストール

$ sudo apt-get install nginx
$ nginx -v
nginx version: nginx/1.4.7

nginxの設定
/etc/nginx/conf.d/default.conf

upstream backends {
    server 127.0.0.1:3000;
}

server {
   listen 80;
    server_name localhost;

    location / {
        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 Host $http_host;
        proxy_pass http://backends;
    }
}

Unicornのインストール

Gemfileにunicornを追加

gem 'unicorn'

bundleでサクッとインストール

$ bundle install

設定ファイルの作成
config/unicorn.rb

# config:utf-8
# unicorn.rb

# process count
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 4)

# 15秒でWorkerをkillしてタイムアウト
timeout 15

# trueにしておくとダウンタイムが発生しないらしい
preload_app true

# 使用するポート番号を指定
listen 3000

# Capistranoを使うときに設定
pid "/path/to/rails/tmp/pids/unicorn.pid"

# ログの設定
stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])

before_fork do |server, worker|
    old_pid = "#{server.config[:pid]}.oldbin"
    if File.exists?(old_pid) && server.pid != old_pid
        begin
            Process.kill("QUIT", File.read(old_pid).to_i)
        rescue Errno::ENOENT, Errno::ESRCH

        end
    end

    defined?(ActiveRecord::Base) and
        ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
    Signal.trap 'TERM' do
        puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
    end

    defined?(ActiveRecord::Base) and
        ActiveRecord::Base.establish_connection
end

def rails_root
    require "pathname"
    Pathname.new(__FILE__) + "../../"
end

taskの作成
lib/tasks/unicorn.rake

namespace :unicorn do

    # Tasks

    desc "Start unicorn"
    task(:start) {
        config = rails_root + "config/unicorn.rb"
        env = ENV['RAILS_ENV'] || "development"
        sh "bundle exec unicorn_rails -D -c #{config} -E #{env}"
    }

    desc "Stop unicorn"
    task(:stop) { unicorn_signal :QUIT }

    desc "Resta unicorn with USR2"
    task(:restart) { unicorn_signal :USR2 }

    desc "Increment number of worker processes"
    task(:increment) { unicorn_signal :TTIN }

    desc "Decrement number of worker processes"
    task(:decrement) { unicorn_signal :TTOU }

    desc "Unicorn pstree (depends on pstree command)"
    task(:pstree) do
        sh "pstree '#{unicorn_pid}'"
    end


    # Helpers

    def unicorn_signal signal
        Process.kill signal, unicorn_pid
    end

    def unicorn_pid
        begin
            File.read(rails_root + "tmp/pids/unicorn.pid").to_i
        rescue Errno::ENOENT
            raise "Unicorn doesn't seem to be running"
        end
    end

    def rails_root
        require "pathname"
        Pathname.new(__FILE__) + "../../../"
    end

end

unicorn起動

$ rake unicorn:start

動作確認

http://localhost/ にアクセスできればおk

その他

参考