🌊

Rails6 + EC2(Amazon Linux2) + RDS + Puma + Nginx の環境構築

2021/08/09に公開

株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。

DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら弊社HPからご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。

  • プロジェクトでRailsエンジニアが足りなくて困っている
  • Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
  • オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい

また、Railsエンジニアも募集しておりますので、興味がありましたら弊社HPからご連絡いただけますと幸いです。

前提

EC2のサーバーで表題の環境構築を行った際の備忘録を残しておきます。
VPCやサブネットなどのAWSコンソールなどの設定に関しては出てきませんのでご注意ください。

開発環境は以下の通りです。

  • Ruby:v2.7.3
  • Ruby on Rails:v6.0.3
  • Webサーバー:Nginx
  • アプリケーションサーバー:Puma v4.3.8(諸々の関係でv4系を利用)
  • Redis(sidekiqで利用):v4.0.3
  • AWSLogs(ログの収集)

環境構築

EC2でログインユーザー発行

bash
# サーバーへec2-userでログインする
ssh -i <pemファイル> ec2-user@ec2-0-0-0-0.ap-northeast-1.compute.amazonaws.com #パブリック IPv4 DNSに記載されている文字列 or 設定したIPアドレス
bash
sudo su #rootユーザーになる
yum update #パッケージのアップデート
useradd <ユーザー名> #ユーザー名のユーザーを作成
passwd <ユーザー名> #ユーザーに対してパスワードを設定

ログインユーザーに対してsudo権限の付与

bash
visudo
bash
#root    ALL=(ALL)       ALLと記載されている下に記載
<ユーザー名>    ALL=(ALL)       ALL

#sudoをパスワードなしで実行したい場合には以下のように記載
<ユーザー名>   ALL=(ALL)       NOPASSWD: ALL

作成したユーザーになるために、以下のコマンドを実行

bash
exit
su <ユーザー名>
cd ~/

ユーザーでのSSHログインを可能にする

.sshフォルダを作成して権限を付与する。

bash
mkdir ~/.ssh
chmod 700 ~/.ssh/

以下のコマンドは自身のPC(Macの場合)にて実行し、id_rsa.pubのキーをコピーする

bash
pbcopy < ~/.ssh/id_rsa.pub
bash
vim ~/.ssh/authorized_keys 
# command + v で内容をペースト
chmod 600 ~/.ssh/authorized_keys #権限を変更しないとsshログインの際に弾かれる
exit #<ユーザー名>からログアウト
exit #サーバーからログアウト

SSHログインでの接続可能時間の変更

通常のままだとSSHログインしている際に、何もしないとすぐに接続が切れるのでそれを長くする。

bash
ssh <ユーザー名>@<IPアドレス>
sudo vim /etc/ssh/sshd_config
sshd_config
#ClientAliveInterval 0
#ClientAliveCountMax 3

上記のような記述があるので以下のように変更して保存

ClientAliveInterval 60
ClientAliveCountMax 120

設定を読み込むためsshdを再起動

bash
sudo systemctl restart sshd

サーバーのタイムゾーンを変更する(必要があれば)

bash
sudo timedatectl set-timezone Asia/Tokyo

Railsアプリケーションに必要なパッケージのインストール

bash
sudo yum install git bzip2 readline-devel zlib-devel gcc libyaml-devel libffi-devel gdbm-devel ncurses-devel gcc-c++ mysql-devel ImageMagick ImageMagick-devel

ruby-build, rbenvのインストール

bash
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
vim ~/.bash_profile

以下の記述を追記

bash
export PATH=$HOME/.rbenv/bin:$PATH
eval "$(rbenv init -)"
bash
source ~/.bash_profile

Ruby, Bundlerのインストール

bash
rbenv install 2.7.3 #時間がかかるので気長に待つ
rbenv rehash
rbenv global 2.7.3
gem install bundler:1.17.1

nvm, NodeJsのインストール

bash
git clone https://github.com/creationix/nvm.git ~/.nvm
vim ~/.bashrc

以下の記述を追記

bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
bash
source ~/.bashrc 
nvm install v6.17.1
npm install -g yarn

Nginxのインストール

bash
sudo amazon-linux-extras install nginx1
sudo vim /etc/nginx/conf.d/rails.conf

以下の内容を記述

rails.conf
client_max_body_size 2G;

upstream app_server {
  server unix:///var/www/<アプリケーション名>/tmp/sockets/puma.sock;
  
  # capistranoのデプロイでは以下のようになる
  # server unix:///var/www/<アプリケーション名>/current/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name <IPアドレス>;
  keepalive_timeout 5;
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;
  root /var/www/<アプリケーション名>/public;
  
  # capistranoのデプロイでは以下のようになる
  # root /var/www/<アプリケーション名>/current/public;

  location ^~ /assets/ {
    gzip_static on;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @app_server;

  location @app_server {
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
  location = /500.html {
  }

  location = /sitemap.xml.gz {
  }

  location = /robots.txt {
  }

  location = /favicon.ico {
  }
}
sudo systemctl start nginx

Redisのインストール(Sidekiq利用のため)

bash
sudo amazon-linux-extras install redis4.0
sudo systemctl start redis

サーバーからGitHubへの接続

キーの作成

bash
ssh-keygen
# すべてEnterで実行する
cat ~/.ssh/id_rsa.pub
# 出てきた文字列を command + Cでコピー

以下はgithub.comで作業

  • GitHubでアプリケーションのリポジトリに遷移
  • アプリケーションのリポジトリで Settings > Deploy keys > Add deploy key
  • 「title」に適切な名前を入れ、「Key」に先ほどの文字列を貼り付け
  • アプリケーションリポジトリのホームに行きsshでのインストールURLをコピー
bash
ssh -T git@github.com
# Hi 〇〇 You've successfully authenticated, but GitHub does not provide shell access. と表示されたらOK

Railsアプリケーションの配置

bash
sudo mkdir -p /var/www
sudo chmod -R 755 /var/www
sudo chown -R <ユーザー名>:<ユーザー名> /var/www
cd /var/www
git clone <先ほどコピーしたsshでのインストールURL>

Railsアプリケーションの設定

bash
cd <アプリケーション>
bundle install
vim config/database.yml

本番環境の設定を記述

database.yml
production:
  <<: *default
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: <アプリケーション名>_production
  pool: 5
  username: <RDSで設定したユーザー名>
  password: <RDSで設定したパスワード>
  socket: /var/lib/mysql/mysql.sock
  host: <RDSのホスト>
bash
bundle exec rails db:create RAILS_ENV=production
bundle exec rails db:migrate RAILS_ENV=production

アセットのコンパイル

bash
bundle exec rails assets:precompile RAILS_ENV=production

Pumaの設定

環境ごとにPumaの設定を読み込みたいためファイルを作成

bash
vim config/puma/production.rb

以下の記述して保存する。

production.rb
# bind "unix://#{Rails.root.join('tmp/sockets/puma.sock')}"だとpumactlコマンドで読み込まないため絶対パスで指定
root_dir = '/var/www/<アプリケーション名>'

max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5)
min_threads_count = ENV.fetch('RAILS_MIN_THREADS', max_threads_count)
threads min_threads_count, max_threads_count

worker_timeout 60

bind "unix://#{root_dir}/tmp/sockets/puma.sock"

environment 'production'

pidfile File.expand_path('tmp/pids/server.pid')

stdout_redirect File.expand_path('log/puma_access.log'), File.expand_path('log/puma_error.log'), true

# workerの数は適宜変更する。指定しない場合はsingle modeとなるが、指定した場合はcluster modeとなる。
workers 2

plugin :tmp_restart

daemonize

Pumaの起動

bash
bundle exec rails s -e production
# このコマンドでconfig/puma/production.rbを参照してくれる

AWSLogsの設定

bash
sudo yum install awslogs
sudo vim /etc/awslogs/awscli.conf

以下の内容を記述して保存。

bash
[plugins]
cwlogs = cwlogs
[default]
region = ap-northeast-1 #利用しているリージョンに変える
bash
sudo vim /etc/awslogs/awslogs.conf
bash
[/var/log/nginx/access.log]
datetime_format = %Y-%m-%dT%H:%M:%S.%f
file = /var/log/nginx/access.log
buffer_duration = 5000
log_stream_name = nginx_access_log
initial_position = start_of_file
log_group_name = production_nginx_access.log

[/var/log/nginx/error.log]
datetime_format = %Y-%m-%dT%H:%M:%S.%f
file = /var/log/nginx/error.log
buffer_duration = 5000
log_stream_name = nginx_error_log
initial_position = start_of_file
log_group_name = production_nginx_error.log

[/var/www/<アプリケーション名>/log/sidekiq.log]
datetime_format = %Y-%m-%dT%H:%M:%S.%f
file = /var/www/<アプリケーション名>/log/sidekiq.log
buffer_duration = 5000
log_stream_name = sidekiq_log
initial_position = start_of_file
log_group_name = production_sidekiq.log

[/var/www/<アプリケーション名>/log/production.log]
datetime_format = %Y-%m-%dT%H:%M:%S.%f
file = /var/www/<アプリケーション名>/log/production.log
buffer_duration = 5000
log_stream_name = production_log
initial_position = start_of_file
log_group_name = production_production.log

[/var/www/<アプリケーション名>/log/puma_access.log]
datetime_format = %Y-%m-%dT%H:%M:%S.%f
file = /var/www/<アプリケーション名>/log/puma_access.log
buffer_duration = 5000
log_stream_name = puma_access_log
initial_position = start_of_file
log_group_name = production_puma_access.log

[/var/www/<アプリケーション名>/log/puma_error.log]
datetime_format = %Y-%m-%dT%H:%M:%S.%f
file = /var/www/<アプリケーション名>/log/puma_error.log
buffer_duration = 5000
log_stream_name = puma_error_log
initial_position = start_of_file
log_group_name = production_puma_error.log

[/var/log/redis/redis.log]
datetime_format = %Y-%m-%dT%H:%M:%S.%f
file = /var/log/redis/redis.log
buffer_duration = 5000
log_stream_name = redis_log
initial_position = start_of_file
log_group_name = production_redis.log

また、AWSでEC2に対してCloudWatchのアクセス権を付与する。

詳細は以下の記事にて書かれているので参照してください。
https://business.ntt-east.co.jp/content/cloudsolution/column-try-28.html

bash
sudo systemctl start awslogsd

サーバー再起動後のアプリケーション立ち上げ

サーバーを再起動した場合に、アプリケーションが自動で立ち上がる設定もすることができます。
以下の記事を参考にしてみてください。
https://zenn.dev/ryouzi/articles/c9223f7ea5df98

Discussion