AWSのEC2でUbuntu+nginx+Unicornの環境構築物語


なれそめ

  • サーバ構築、フレームワークの導入に慣れよう
  • ウェブサービスを自分一人で作れるようになるための練習

概要

  • 自分が慣れるため、今後のメモのためという意味合いが強いです
  • unicornとしての機能には触れません

環境

  • Ubuntu 16.04.2 LTS
  • nginx/1.10.0 (Ubuntu)
  • ruby 2.4.0p0
  • rbenv 1.1.0
  • Bundler version 1.14.6
  • unicorn 5.2.0

1.サーバ初期設定

  1. AWSでEC2インスタンス作成(Ubuntuを選択)
  2. セキュリティグループ設定:自分の利用する回線(送信元)で、指定したポートでSSH接続するために解放する(任意のポート)
  3. AWSで接続のコマンドを用意してくれるのでそれを利用してターミナルからSSHでアクセス
ssh接続の設定

セキュリティを最低限強くするため、22番での接続を禁止し、rootでのログインも禁止する

$ sudo vim /etc/ssh/sshd_config
Port 55555 // 任意のポート番号に変更
PermitRootLogin no // noに変更
$ sudo /etc/init.d/ssh restart

これで22番ポートでのログインが禁止され、以下のようにポートを指定してログインができる

sudo ssh -p 55555 -i "key.pem" [email protected]

sshの設定を変更したらrestartして反映させる

作業ユーザ設定

sudo権限も付与しておく

$ sudo useradd -m sasaki
$ sudo passwd sasaki
$ sudo usermod -G sudo sasaki
$ su - sasaki

2.bundler導入とrailsプロジェクト作成

  1. ruby用ライブラリ(gem)の管理するためにbundlerを用いる
  2. gemコマンドでbundlerをインストール
  3. Gemfileを編集してrailsのインストールの準備
$ sudo apt update
$ sudo apt-get install bundler
$ mkdir rails-app/ && cd rails-app/
$ bundle init
$ vi Gemfile
# A sample Gemfile
source 'https://rubygems.org'

gem 'rails', '>= 5.0.0.1'
gem 'sqlite3'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'therubyracer', platforms: :ruby
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc
gem 'bcrypt', '~> 3.1.7'
gem 'unicorn'

group :development, :test do
  gem 'byebug'
  gem 'web-console', '~> 2.0'
  gem 'spring'
end
$ bundle install --path vendor/bundle
$ bundle exec rails new .

ここで僕はsqlite3がないよと怒られたのでapt-getで入れました

$ sudo apt-get install libsqlite3-dev

3.rubyとrbenvの用意

$ cd ~/rails-app/
$ git clone https://github.com/sstephenson/rbenv.git .rbenv
$ git clone https://github.com/sstephenson/ruby-build.git .rbenv/plugins/ruby-build
$ sudo apt update
$ vi ~/.bashrc


```.bashrc
+ [[ -d ~/rails-app/.rbenv  ]] && \
+   export PATH=${HOME}/rails-app/.rbenv/bin:${PATH} && \
+   eval "$(rbenv init -)"
$ source ~/.bashrc

4.アプリケーション作成へ

$ cd ~/rails-app/
$ bundle exec rails generate scaffold board title:string text:string

ここでエラーが発生、よく出るエラーところらしい
エラーが出たら以下のようにコメントアウトを外すして改めてbundle installすると成功うまく行く場合が多い

$ vi Gemfile
- # gem 'therubyracer', platforms: :ruby
+ gem 'therubyracer', platforms: :ruby
$ bundle install
$ bundle exec rails generate scaffold board title:string text:string

rakeコマンドが使えるのでrakeでDBのマイグレート

$ rake db:migrate
$ vi config/routes.rb
routes.rb
...
+  root "boards#index"
end
...

以下のコマンドでサーバを起動(ctrl+C)でキャンセルできる

$ bundle exec rails server -b 0.0.0.0

他にもタブを開いて確認して見ると確認ができる

$ ps aux | grep 0.0.0.0:3000
sasaki  24821  1.0  7.2 751628 73444 pts/1    Sl+  04:27   0:01 puma 3.8.2 (tcp://0.0.0.0:3000) [rails-app]

5.unicorn設定

unicorn.rbについては
ここのを参考にした

$ cd ~/rails-app/config/ && vi unicorn.rb
unicorn.rb
# -*- coding: utf-8 -*-
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true  # 更新時ダウンタイム無し

listen File.expand_path('/tmp/sockets/unicorn.pid', __FILE__)
pid File.expand_path('/tmp/pids/unicorn.pid', __FILE__)
listen "/tmp/sockets/unicorn.sock"
pid "/tmp/pids/unicorn.pid"

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  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

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

rakeコマンドでユニコーンの起動や停止を行うために以下の編集を行う
こちらも先ほどのQiitaを参考にしました

$ bundle exec rails generate task unicorn
$ cd ~/rails-app/ && vi lib/tasks/unicorn.rake
unicorn.rake
namespace :unicorn do
  ##
  # Tasks
  ##
  desc "Start unicorn for development env."
  task(:start) {
    config = Rails.root.join('config', 'unicorn.rb')
    sh "bundle exec unicorn_rails -c #{config} -E development -D"
  }

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

  desc "Restart 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

  def unicorn_signal signal
    Process.kill signal, unicorn_pid
  end

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

これで以下のようなコマンドが使える

rake unicorn:start
rake unicorn:stop

6.nginx導入とブラウザで確認

$ sudo apt-get install -y nginx
$ /etc/init.d/nginx start
$ /etc/init.d/nginx status

これでnginxが Active: active (running) であることを確認できるはず

nginxとのやりとりにはソケットを使う
conf.dにconfファイルを置けばそれが読まれる設定になっている

$ cd /etc/nginx/conf.d/
$ sudo vi local.conf
local.conf
upstream unicorn {
  server unix:/tmp/sockets/unicorn.sok;
}

server {
  listen 80 default_server;
  server_name localhost-rails;

  access_log /var/log/nginx/sample_access.log;
  error_log /var/log/nginx/sample_error.log;

  root /home/sasaki/rails-app/app/views/boards;

  client_max_body_size 100m;
  error_page 404 /404.html;
  error_page 500 502 503 504 /500.html;
  try_files $uri/index.html $uri @unicorn;

  location @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://unicorn;
  }
}
$ sudo vi ../nginx.conf
nginx.conf
- include /etc/nginx/sites-enabled/*;
+ # include /etc/nginx/sites-enabled/*; 

以下のようにそれぞれのファイルで同じ場所のsockファイルを見るように設定されていることが必要
違ってたら揃える

/etc/nginx/conf.d/local.conf
server unix:/tmp/sockets/unicorn.sock;
unicorn.rb
listen "/tmp/sockets/unicorn.sock"
pid "/tmp/pids/unicorn.pid"

sockファイルの置き場は工夫の余地があるかと
AWSを用いているのでブラウザから見れるようにセキュリティグループに追加し
nginx再起動させてhttp://でアクセス

$ /etc/init.d/nginx restart

うまくいかないとき

nginxのログ(上記の設定だと)

$ sudo tail -f /var/log/nginx/sample_access.log
$ sudo tail -f /var/log/nginx/sample_error.log