この記事での注意
この作業はローカル環境からの作業とサーバーでの作業が複雑に入り交じっています。その為、ターミナルで実行するコマンドの説明に「ローカル」「サーバー」と記載しています。お間違えないように気をつけてください。
アプリケーション名を「sample611」 としています。ご自身のアプリケーション名に読み替えてご参考ください。
サーバーにインストールする環境
- Amazon Linux 2
- Ruby 2.7.2 (rbenv)
- Rails 6.1
- MySQL or PostgreSQL
- Nginx + Puma 5
- Node.js 12
- Yarn
本番サーバーの構築
本番サーバーのEC2のOSがAmazon Linux2の場合の設定手順を紹介します。
##1. システムライブラリアップデート
まずはAmazon Linux 2のシステムライブラリを更新します。
$ sudo yum update -y
##2. タイムゾーン、ロケール
日本での運用する場合はタイムゾーンと言語の設定を日本にした方がわかりやすいと思います。
$ sudo timedatectl set-timezone Asia/Tokyo
$ sudo localectl set-locale LANG=ja_JP.UTF-8
##3. NTP
サーバーの時刻のずれを自動で補正するタイムサーバーの設定を行います。
$ yum info chrony
$ chronyc sources -v
##4. 標準パッケージインストール
Rubyのインストールなどで必要になるライブラリをインストールします。
$ sudo yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel git
##5. データベースモジュールのインストール
Railsからデータベースにアクセスするためのアダプタをインストールする必要がありますが、そのインストールに必要なライブラリをデータベース別にインストールします。
- PostgreSQLの場合
$ sudo yum -y install postgresql-devel
- MySQLの場合
$ sudo yum -y install mysql-devel
##6. Rubyのインストール
Railsを動かすためにはRubyのインストールが必要です。いろんなインストール方法がありますが、Rubyのバージョンを切り替えることができるrbenvを使った方法を説明します。
###6.1 rbenvのインストール
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
$ rbenv -v
###6.2 ruby-buildのインストール
$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ cd ~/.rbenv/plugins/ruby-build
$ sudo ./install.sh
$ rbenv install -l
###6.3 Rubyのインストール
rbenvとruby-buildをインストールが終わったので、Rubyのインストールを行います。
$ rbenv install 2.7.2
$ rbenv global 2.7.2
rubyのインストールにはすこし時間がかかります。
rbenv globalでシステム全体で使用するRubyのバージョンを指定しています。
##7. Rails 6で必要なモジュールのインストール
###7.1 Node.jsのインストール
Rails 6からは Node.js や Yarn が必要になりました。Node.jsはサーバーサイドでのJavaScript実行環境で、Yarnはfacebook製のJavaScriptのパッケージマネージャーです。
$ curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -
$ sudo yum install -y nodejs
$ sudo npm install -g n
$ sudo n stable
$ sudo ln -snf /usr/local/bin/node /usr/bin/node
###7.2 Yarnのインストール
$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ sudo yum install yarn -y
##8. Railsのインストール
Rails 6のインストールを行います。gem install railsでもインストールできますが、ここではパッケージ管理ソフトbundlerからインストールする方法を紹介します。
$ cd ~
$ mkdir rails
$ cd rails
$ bundle init
$ vim Gemfile
(gem "rails"をコメントアウト解除)
$ bundle install
$ bundle exec rails -v
(インストールされたことを確認)
$ cd ..
$ rm -rf rails
データベースの設定
##9. 本番データベースの作成
ここではRDSの設定については詳しく説明しません。すでにRDSにデータベースが設定されていることを前提に進めていきますが、下記をご確認ください。
- RDSにて作成したデータベースのユーザー名、パスワード、データベースエンドポイントをご確認ください。
- RDSのセキュリティグループでウェブサーバーとなるEC2のセキュリティグループのアクセス許可を設定してください。
##10. Railsアプリと本番データベースの接続設定
Railsとデータベースの接続設定を行います。データベースの設定にはデータベースにアクセスするためのパスワードが含まれますが、これを直接database.ymlに記載すると、github上でパスワードを知ることができてしまい危険です。
こういった機密情報は config/credentials.yml.enc にセットします。(Rails5.2以降で可能)
このファイルはエディタで表示すると暗号化された文字列になっていますが、 master.key を使うことで閲覧、編集することができます。この credentials.yml.enc と master.key の関係を理解しておいてください。
次のコマンドでcredentials.yml.encを編集します。ここではエディタをvimに指定しています。
$ EDITOR=vim bin/rails credentials:edit
下記のようにdbの項目を追記し、RDS作成時に設定したユーザー名、パスワード、データベースエンドポイントを記述します。
# aws:
# access_key_id: 123
# secret_access_key: 345
# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
db:
username: (username)
password: (password)
host: (database endpoint)
終わったら、:wqでエディタを終えます。
次に本番環境において、データベースの設定が適用されるようconfig/database.ymlを編集します。database.ymlの最後の方にproductionの項があります。そこを下記のように修正します。
production:
<<: *default
database: sample611_production
username: <%= Rails.application.credentials.db[:username] %>
password: <%= Rails.application.credentials.db[:password] %>
host: <%= Rails.application.credentials.db[:host] %>
port: 5432
Rails.application.credentials.dbとすることでcredentials.yml.encのdbの項を読みにいきます。
portはデータベースで使用するポートを指定します。一般的にはPostgreSQLの場合は 5432、MySQLの場合は 3306 になります。
ここで、改修したコードをいったんコミットし、githubへプッシュしましょう。
$ git add .
$ git commit -m "Setup database"
$ git push origin master
#デプロイ設定
デプロイツールCapistranoを使ったデプロイの設定を行います。
##11. Capistranoのインストール
Capistranoをインストールします。下記のようにGemfileのdevelopmentグループにcapistrano, capistrano-rails, capistrano-rbenvを追加し、bundle installします。
group :development do
gem "capistrano", "~> 3.14", require: false
gem "capistrano-rails", "~> 1.6", require: false
gem 'capistrano-rbenv', '~> 2.2'
end
$ bundle install
$ bundle exec cap install
##12. Capfileの設定
下記のようにCapfileに追記します。
:
# require "capistrano/rails/migrations"
# require "capistrano/passenger"
require 'capistrano/rails'
require 'capistrano/rbenv'
:
##13. デプロイの設定
Capistranoのデプロイ設定を行います。全体的なデプロイの設定を「config/deploy.rb」、本番環境用の設定を「config/deploy/production.rb」に記述します。
lock "~> 3.15.0"
set :application, "sample611"
# 自分のリポジトリを設定
set :repo_url, "git@github.com:yukeippi/sample611.git"
# rbenvの設定
set :rbenv_type, :user
set :rbenv_ruby, '2.7.2'
# Railsアプリの設置先
set :deploy_to, "/var/rails/sample611"
# 共有ファイルの設定
append :linked_files, "config/master.key"
# 共有ディレクトリの設定
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
# リリース保存数
set :keep_releases, 5
linked_filesはデフォルトではconfig/database.ymlとなっていますが、config/master.keyに変更してください。
次にconfig/deploy/production.rbを編集します。
下記の (server ip) にはデプロイ先EC2のIPをセットしてください。
githubへのキー登録については下記をご参照ください。
set :rails_env, 'production'
set :branch, 'master'
# githubへの設定
set :ssh_options, {
auth_methods: [ 'publickey' ],
keys: [ '~/.ssh/aws.pem' ],
}
server '(server IP)', user: 'ec2-user', roles: %w{app db web}
区切りが良いので、ここでいったんコミット、プッシュしましょう。(プッシュは任意です)
$ git add .
$ git commit -m "Setup capistrano"
$ git push oririn master
##14. Githubへのキー登録
デプロイ時にデプロイ先サーバーがgithubからソースコードを取得するための設定を行います。
この設定は下記の記事をご参照ください。
##15. デプロイ先ディレクトリの作成
Railsアプリのプログラムの設置(デプロイ)を行います。アプリケーションの設置場所を「/var/rails」、実行者を「ec2-user」とした場合、下記のコマンドを実行し、ディレクトリを作ります。
$ cd /var/
$ sudo mkdir rails
$ sudo chown ec2-user:ec2-user rails
ここで「cap deploy:check」を実行しますが、下記のように失敗します。この処理の目的は、Capistranoにデプロイに必要なディレクトリを作らせることです。
$ bundle exec cap production deploy:check
00:02 deploy:check:make_linked_dirs
01 mkdir -p /var/rails/sample611/shared/config
✔ 01 ec2-user@(server IP) 0.078s
00:02 deploy:check:linked_files
ERROR linked file /var/rails/sample611/shared/config/master.key does not exist on (server IP)
エラーメッセージにあるように「master.key」がないことが原因です。サーバーに入って下記のようにmaster.keyを作成してください。
$ cd /var/rails/sample611/shared/config/
$ vim master.key
(ローカルにあるmaster.keyを貼り付け)
これで問題は解決しましたので、再度、デプロイチェックを行います。
$ bundle exec cap production deploy:check
成功するはずです。これでデプロイ先ディレクトリができました。
##16. Databaseのcreate
しかし、まだこの時点でもデプロイ途中で失敗します。それはデータベースがcreateされていないからです。deployでデータベースのmigrateは実行しますが、createしていないため、migrateできずに失敗してしまいます。
そこで、失敗前提でデプロイを実行し、そのときにデプロイされたソースコードを使ってcreateします。
$ bundle exec cap production deploy
最初はgemをインストールするため、時間がかかります。
しばらく待つとデプロイは終わり、途中で失敗していることが確認できます。その後、本番サーバーに入り、下記のようにデプロイされたソースコードのルートに移動し、データベースを作成します。
$ cd /var/rails/sample611/releases/(最新リリース)/
$ bundle exec rails db:create RAILS_ENV=production
(最新リリース)は「20210216104333」といったディレクトリ作成日時を意味するディレクトリを指します。ソースコードがデプロイされると、Capistranoがこのようなディレクトリを作成し、そこにプログラムを保存します。
これでデータベースが作成されたら、デプロイが可能になります。
再度デプロイします。
$ bundle exec cap production deploy
これで成功するはずです。
WebサーバーとRailsアプリの連携
##17. Pumaの設定
本番環境のPumaの設定を行います。
# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
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
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch("PORT") { 3000 }
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "production" }
# Specifies the `pidfile` that Puma will use.
# pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
# preload_app!
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
bind "unix:///var/rails/sample611/shared/tmp/sockets/puma.sock"
RAILS_ENVをproductionに指定しているところと、最下行でsocketを指定しているのがポイントです。
ここでいったんコミット、プッシュしてください。
$ git add .
$ git commit -m "Setup puma for production"
$ git push origin master
##18. Nginxのインストール
ここからはサーバーでの作業になります。
サーバーにNginxをインストールします。
$ sudo amazon-linux-extras install nginx1 -y
##19. NginxとPumaの紐付け
次にNginxとPumaを紐付けるための設定ファイルを作成します。ポイントはuptreamの設定、rootの指定、proxy_passの指定です。
$ sudo vim /etc/nginx/conf.d/sample611.conf
upstream puma {
server unix:///var/rails/sample611/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name example.com;
root /var/rails/sample611/current/public;
try_files $uri/index.html $uri @railsapp;
location @railsapp {
proxy_pass http://puma;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
upstream puma内にあるpuma.sockのパスに気をつけてください。これは15のbindで設定したパスにあわせなければなりません。
##20. Pumaのサービス設定
次にpumaをsystemctlで起動や再起動ができるように設定を行います。
$ sudo vim /etc/systemd/system/puma.service
[Unit]
Description=Puma HTTP Server
After=network.target
[Service]
Type=simple
Environment="RAILS_ENV=production"
WorkingDirectory=/var/rails/sample611/current
ExecStart=/home/ec2-user/.rbenv/shims/bundle exec /var/rails/sample611/shared/bundle/ruby/2.7.0/bin/puma -C /var/rails/sample611/current/config/puma/production.rb
Restart=always
[Install]
WantedBy=multi-user.target
ここでpumaの実行パスや実行時の設定ファイルを指定しています。
あと、このままでは実行権限がないため、下記のコマンドでpuma.serviceに実行権限を付与してください。
$ sudo chmod +x /etc/systemd/system/puma.service
これでサーバー側の設定は終わりです。
##21. Puma, Nginxの起動
いよいよウェブサーバー、アプリケーションサーバーの起動です。まず、Pumaを起動します。
$ sudo systemctl daemon-reload
$ sudo systemctl start puma
下記のコマンドで起動を確認します。
$ sudo systemctl status puma
● puma.service - Puma HTTP Server for sample611 (production_mysql)
Loaded: loaded (/etc/systemd/system/puma.service; enabled; vendor preset: disabled)
Active: active (running) since 土 2021-02-20 15:47:30 JST; 27min ago
Main PID: 2876 (bundle)
CGroup: /system.slice/puma.service
└─2876 puma 5.1.1 (tcp://0.0.0.0:3000,unix:///var/rails/sample611/shared/tmp/sockets/puma.sock) [20210216072308]
上記のようになければ「Active: active」になっていれば、起動成功です。
もし「Active: inactive」になっていれば、何かしらの設定に間違いがある可能性があります。
journalctl -xe等を使って原因を調べてください。
次にnginxの起動します。
$ sudo systemctl start nginx.service
これでブラウザを使って下記のようにサイトにアクセスすれば画面に表示されるはずです。
http://(サイトのIP)/
##21. デプロイ時のリスタート設定
プログラムをデプロイしたときはアプリケーションサーバーをリスタートする必要があります。capistranoのrestartタスクを追加しておくと、それも自動で実行してくれます。
namespace :deploy do
task :restart do
on roles(:web), in: :sequence, wait: 5 do
within release_path do
execute "sudo systemctl daemon-reload"
execute "sudo systemctl restart puma"
end
end
end
after :finishing, :restart
end
これでローカル側のコード改修が終わりです。
最後にここまでをコミットしましょう。
$ git add .
$ git commit -m "Setup restart puma"
再起動することを確認するため、デプロイします。
$ bundle exec cap production deploy
:
00:34 deploy:cleanup
Keeping 5 of 6 deployed releases on (server IP)
01 rm -rf /var/rails/sample611/releases/20210314010936
✔ 01 ec2-user@(server IP) 0.797s
00:35 deploy:restart
01 sudo systemctl daemon-reload
✔ 01 ec2-user@(server IP) 0.199s
02 sudo systemctl restart puma
✔ 02 ec2-user@(server IP) 0.094s
00:35 deploy:log_revision
01 echo "Branch master (at 0e3b185044e3a56f20a3bf37d7c6ce31f5a92b54) deployed as release 20210314015609 b…
✔ 01 ec2-user@(server IP) 0.119s
デプロイログからrestartが実行されていることがわかると思います。
これでデプロイは成功です!お疲れ様でした。
puma, nginxの自動起動設定
最後にpuma,nginxの自動起動設定を行っておくとよいでしょう。これを行うことでサーバーを再起動しても自動でWebアプリケーションを起動してくれます。
$ sudo systemctl enable puma.service
$ sudo systemctl enable nginx.service
以上です。