プログラミング備忘録【Ruby on Rails】

初学者として日々学んだことや発見をいつでも引き出せるようブログにまとめてみた。初学者のため間違った説明があった場合、コメントいただけると嬉しいです。

AWS EC2にNginx,Unicorn,Capistranoを使ってデプロイしてみた!

AWSアカウント作成時にやっておくべき初期設定

https://note.com/kuyo/n/n49b56b1448b1

デプロイの流れ

デプロイ環境
ruby 2.6.5
rails 5.2.3
capistrano 3.6.0

前提条件
AWSのEC2インスタンスが作成されており、キーペアと関連づけられている前提。
*アプリ名はachieveとする

1.キーペアによるSSH接続、EC2の初期設定について

1.キーペアへの読み取り権限付与

$ cd ~/Downloads
$ chmod 400 キーペア名
例:$ chmod 400 achieve-key.pem

2.EC2へログイン

$ ssh -i "キーペア名" ec2-user@パブリックIP
例:ssh -i "achieve-key.pem" ec2-user@13.113.254.221
*ec2-userはデフォルトのユーザ名
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '52.193.249.209' (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

<https://aws.amazon.com/amazon-linux-ami/2016.03-release-notes/>
6 package(s) needed for security, out of 15 available
Run "sudo yum update" to apply all updates.

3.管理者権限に切り替え
[ec2]

$ sudo su -

・ec2-userからrootに切り替わる(*rootはLinuxの管理者名を表す)

[ec2-user@ip-1-250 ~]$ sudo su -
[root@ip-172-31-29-250 ~]#


4.パッケージ管理ソフトウェアのyumを最新にする(yumとはRedHat系と呼ばれるLinuxで使用されているパッケージ管理システム)
[ec2]

$ yum update -y

5.タイムゾーンJST(日本時間)に変更
[ec2]

$ ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ vi /etc/sysconfig/clock

・元の設定を削除し、以下の設定を記述し保存

ZONE="Asia/Tokyo"
UTC=false

6.言語を日本語に変更
[ec2]

$ vi /etc/sysconfig/i18n

・元の設定を削除し、以下の設定を記述し保存

LANG=ja_JP.UTF-8


7.使用する国の環境に最適化する
[ec2]

$ vi /etc/cloud/cloud.cfg


・元の設定を削除し、以下の設定を記述し保存

repo_upgrade: none
locale: ja_JP.UTF-8


8.swap領域の作成
[ec2]

$ dd if=/dev/zero of=/swapfile bs=1M count=1024
$ mkswap /swapfile
$ swapon /swapfile
$ vi /etc/fstab


・以下の内容を追記

/swapfile swap swap defaults 0 0


9.新規ユーザ作成
・デフォルトユーザであるec2-userで開発するのはセキュリティ的に危険であるため、新しくユーザを作成し、今後はそのユーザで開発するようにします。
[ec2]

$ useradd app -G wheel *appがユーザー名、wheelがグループ名
$ visudo

・# %wheel ALL=(ALL) NOPASSWD: ALLのコメントアウトを解除(コメントを解除することで、wheelグループに属するユーザは、パスワードを入力する必要がなくなる)
10.ec2からログアウト(ローカルに戻るため、2度exitする必要がある)
[ec2]

$ exit
$ exit

2.公開鍵によるEC2インスタンスSSH接続について

1.Githubの公開鍵の中身を表示し、コピーする

$ cat ~/.ssh/id_rsa.pub

2.公開鍵をEC2上に設置
[ec2]

$ sudo su app
$ cd ~
$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ touch authorized_keys
$ chmod 600 authorized_keys
$ vi authorized_keys

・コピーしておいた公開鍵の中身を貼り付け
3.公開鍵でSSH接続する
秘密鍵の所在をpwdコマンドで確認

$ cd ~/.ssh

$ pwd

SSH接続

$ ssh -i "pwdで確認したpath/id_rsa" app@パブリックIP
例:ssh -i "/Users/Sato/.ssh/id_rsa" app@13.113.254.221

*今までec2-userとしてログインしていたものがappでログインするようになる。
4.タイムゾーンが日本時間(JST)に変更されているか確認
[ec2]

$ date
*下記内容が出力できればOK
表示例:2017年  10月 25日 水曜日 18:02:29 JST

5.crondの時刻のズレを修正するためにcrondを再起動
[ec2]

$ sudo service crond restart

6.crondはプロセスを再起動しただけでは修正されないのでインスタンスの再起動
[ec2]

$ sudo reboot

7.再度ec2にログインし、デフォルトのユーザであるec2-userを削除
[ec2]

$ sudo su -
$ userdel ec2-user

EC2インスタンス内部の環境構築について

8.各種機能のインストール
[ec2]
⑴gitのインストール

$ yum -y install git
$ git --version

⑵rbenvのインストール

$ git clone https://github.com/rbenv/rbenv.git /usr/local/rbenv

・rbenvをシステムワイドに利用するための環境変数を設定
$ vi /etc/profile.d/rbenv.sh
・以下の内容を記述
export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

・変更を反映させる
$ source /etc/profile.d/rbenv.sh

ruby-buildのインストール

$ git clone https://github.com/rbenv/ruby-build.git /usr/local/rbenv/plugins/ruby-build


Rubyをインストールするためのツール、ライブラリをインストール

$ yum -y groupinstall "Development Tools"
$ yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel mysql-devel readline-devel
$ yum -y install ImageMagick ImageMagick-devel

gccのダウングレード

$ yum install gcc44
$ alternatives --set gcc /usr/bin/gcc44

Rubyのインストール&設定

$ rbenv install 2.6.3 *アプリと同じバージョンを指定
$ rbenv global 2.6.3
$ rbenv rehash
・念のため、インストールされているか確認
$ ruby -v

19.appユーザー上の設定変更
[ec2]

・rbenvのコマンドを実行できるようにする
$ exit *appユーザーに戻る
$ cd /usr/local/rbenv/
$ sudo chown app version
$ sudo chown app shims
$ rbenv rehash????????????????????????????
・rubyのバージョン変更
$ rbenv global 2.6.3
$ rbenv rehash

20.bundlerのインストール
[ec2]

$ sudo su -
$ rbenv exec gem install bundler
$ rbenv rehash
・正しくインストールされているか確認
$ which bundler
・以下のように返ってくればOK
/usr/local/rbenv/shims/bundler

21.PostgreSQLのインストール&初期設定
[ec2]

$ yum -y install postgresql94 postgresql94-server postgresql94-devel postgresql94-contrib postgresql94-docs

⑴初期設定

$ /etc/init.d/postgresql94 initdb

⑵起動

$ /etc/init.d/postgresql94 start

⑶設定ファイルの編集

$ vi /var/lib/pgsql94/data/postgresql.conf
・三番目のトピックにある「listen_addresses」のコメントを解除し、設定を'localhost'から'*'に編集

⑷認証設定を編集

$ vi /var/lib/pgsql94/data/pg_hba.conf
・最下部に、以下を追記
local   all     all     trust
host    all     all     0.0.0.0/0       md5
・以下のようにコメントアウト
# "local" is for Unix domain socket connections only
# local   all             all                               peer
# IPv4 local connections:
# host    all             all             127.0.0.1/32       ident
# IPv6 local connections:
# host    all             all             ::1/128             ident
・再起動
$ /etc/init.d/postgresql94 restart

22.データベースを作成
[ec2]
⑴postgresというユーザー名で、PostgreSQLへ接続

$ psql -U postgres

⑵データベース上の権限設定

CREATE ROLE "ロール名" WITH SUPERUSER LOGIN;
CREATE DATABASE "データベース名";

CREATE ROLE "sample" WITH SUPERUSER LOGIN;
CREATE DATABASE "sample_production";

*ロール名とデータベース名は[config/database.yml]の最下部

production:
  <<: *default
  database: sample_production ←データベース名
  username: sample ←ロール名
  password: <%= ENV['AWS_APP_DATABASE_PASSWORD'] %>

⑶再起動&PostgreSQLとの接続を解除

$ /etc/init.d/postgresql94 restart
$ \q

23.Nginxのインストール
[ec2]

$ yum -y install nginx
・自動起動させる設定
$ chkconfig nginx on
・起動
$ /etc/init.d/nginx start
・EC2インスタンスのIPアドレスにアクセスし、「Welcme to nginx」が表示されていればOK

24.EC2〜Github間でSSH接続ができるよう設定
[ec2]

$ sudo su app 
$ cd
・EC2上で公開鍵秘密鍵のペアを作成
$ ssh-keygen -t rsa *入力画面が出てきますが、全てエンター
・公開鍵をコピーし、GithubのSSHkeyに追加
$ cat ~/.ssh/id_rsa.pub

25.アプリ公開用ディレクトリを作成
[ec2]

$ cd /var
$ sudo mkdir www
$ sudo chown -R app:app www
$ cd /var/www

26.デプロイするアプリのディレクトリへ移動
⑴gemfileに以下のgemを追記

  gem 'dotenv-rails' # 開発環境で環境変数を操作するのに必要
  gem 'unicorn' # アプリケーションサーバのunicorn
  gem 'mini_racer', platforms: :ruby # デプロイ時に必要
  group :development, :test do
    gem 'capistrano', '3.6.0' # capistranoのツール一式
    gem 'capistrano-bundler'
    gem 'capistrano-rails'
    gem 'capistrano-rbenv'
    gem 'capistrano3-unicorn'
  end

  group :development do
    gem 'ed25519'
    gem 'bcrypt_pbkdf'
  end

⑵インストール

$ bundle install

Capistranoの設定ファイル[Capfile]を作成

$ bundle exec cap install

⑷[Capfile]に以下を追記*重複しているものは追記不要

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'

⑸[config/deploy/production.rb]の内容をすべて削除し、以下を記述

server 'EC2のIPアドレス', user: 'app', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵へのpath'

server '12.34.56.78', user: 'app', roles: %w{app db web}
set :ssh_options, keys: '/Users/Sato/.ssh/id_rsa'

⑷[config/deploy.rb]の内容をすべて削除し、以下を記述

# config valid only for current version of Capistrano
lock '3.6.0'
# デプロイするアプリケーション名------------①
set :application, 'achieve'
# cloneするgitのレポジトリ
# (xxxxxxxx:ユーザ名、yyyyyyyy:アプリケーション名)-------------------②
set :repo_url, 'https://github.com/xxxxxxxxx/yyyyyyyyy'
# deployするブランチ。デフォルトはmasterなのでなくても可。
set :branch, ENV['BRANCH'] || 'master'
# deploy先のディレクトリ-------------③
set :deploy_to, '/var/www/achieve'
# シンボリックリンクをはるフォルダ・ファイル
set :linked_files, %w{.env config/secrets.yml}
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets public/uploads}
# 保持するバージョンの個数(※後述)
set :keep_releases, 5
# Rubyのバージョン-------------------④
set :rbenv_ruby, '2.5.1'
set :rbenv_type, :system
# 出力するログのレベル。エラーログを詳細に見たい場合は :debug に設定する。
# 本番環境用のものであれば、 :info程度が普通。
# ただし挙動をしっかり確認したいのであれば :debug に設定する。
set :log_level, :info
namespace :deploy do
  desc 'Restart application'
  task :restart do
    invoke 'unicorn:restart'
  end
  desc 'Create database'
  task :db_create do
    on roles(:db) do |host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:create'
        end
      end
    end
  end
  desc 'Run seed'
  task :seed do
    on roles(:app) do
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:seed'
        end
      end
    end
  end
  after :publishing, :restart
  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
    end
  end
end

Unicornの設定ファイルを作成
config/unicorn/production.rbを作成し、以下を記述(①~④を修正してください)

$worker  = 2
$timeout = 30
#自分のアプリケーション名(currentがつくことに注意)
$app_dir = "/var/www/アプリケーション名/current"
$listen  = File.expand_path 'tmp/sockets/unicorn.sock', $app_dir
$pid     = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir
# 上記で設定したものが適応されるよう定義
worker_processes  $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen  $listen
pid $pid
preload_app true
before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      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

27.アプリの変更内容をGithubへpush

git add -A
git commit -m "init unicorn"
git push origin master

28.Nginxの設定ファイルを新規作成
[ec2]
⑴設定ファイルを作成

$ sudo vi /etc/nginx/conf.d/アプリケーション名.conf

⑵以下を追記

upstream unicorn {
    server unix:/var/www/アプリケーション名/shared/tmp/sockets/unicorn.sock;
}
server {
        listen       80;
        server_name  EC2のIPアドレス;

        root /var/www/アプリケーション名/shared/public;
            access_log /var/log/nginx/アプリケーション名_access.log;
            error_log /var/log/nginx/アプリケーション名_error.log;
            location ~ ^/assets/ {
            }
            location / {
                    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 nginx -s reload

29.現時点でデプロイを実行しても問題がないか、チェック
[ローカル下]

$ bundle exec cap production deploy:check
<span style="font-size: 80%">*「ERROR linked file /var/www/achieve/shared/.env does not exist on xx.xxx.xxx.x」はここでは無視してOK</span>

ここでもし他のエラーが出るようであれば、どこかに問題あり

30.環境変数を登録
⑴アプリのシークレットキーを登録

・シークレットキーを表示し、コピー
$ bundle exec rake secret

[ec2]

$ cd /var/www/アプリケーション名/shared/config
$ vi secrets.yml
・以下を記述
production:
  secret_key_base: コピーしたシークレットキー

環境変数を設定するshared/.envを作成

$ cd /var/www/アプリケーション名/shared
$ vi .env
・必要な環境変数を記述

31.デプロイ実行

$ bundle exec cap production deploy
・unicornの起動
$ cap production unicorn:stop
$ cap production unicorn:start

・IPアドレスにアクセスし、アプリが表示されていれば成功

覚えておきたいコマンド

[ローカル]
・unicornの停止
$ bundle exec cap production unicorn:stop
・unicornの起動
$ bundle exec cap production unicorn:start

[ec2]
・nginxの設定ファイルの変更
$ vi /etc/nginx/nginx.conf
・nginxの停止
$ sudo /etc/init.d/nginx stop
・nginxの起動
$ sudo /etc/init.d/nginx start
・nginxの再起動
$ sudo nginx -s reload
・nginx アクセスログ
$ cat /var/log/nginx/アプリケーション名_access.log;
・unicornログ
$ cat /var/www/アプリケーション名/shared/log/unicorn.log;
・本番環境でのrails sのようにログを表示させる
$ cd /var/www/アプリケーション名/current/log
$ tailf production.log
・本番環境でのrails cのようにコマンド実行
$ cd /var/www/アプリケーション名/current
$ bundle exec rails c production
・本番環境でのデータベースのリセット(先にunicornを停止させる必要がありそう)
$ cd /var/www/アプリケーション名/current
$ bundle exec rake db:reset RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1