LoginSignup
3
3

More than 3 years have passed since last update.

Rails 6アプリをAWSへのデプロイする手順

Last updated at Posted at 2021-03-14

この記事での注意

この作業はローカル環境からの作業とサーバーでの作業が複雑に入り交じっています。その為、ターミナルで実行するコマンドの説明に「ローカル」「サーバー」と記載しています。お間違えないように気をつけてください。

アプリケーション名を「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.jsYarn が必要になりました。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にデータベースが設定されていることを前提に進めていきますが、下記をご確認ください。

  1. RDSにて作成したデータベースのユーザー名、パスワード、データベースエンドポイントをご確認ください。
  2. RDSのセキュリティグループでウェブサーバーとなるEC2のセキュリティグループのアクセス許可を設定してください。

10. Railsアプリと本番データベースの接続設定

Railsとデータベースの接続設定を行います。データベースの設定にはデータベースにアクセスするためのパスワードが含まれますが、これを直接database.ymlに記載すると、github上でパスワードを知ることができてしまい危険です。

こういった機密情報は config/credentials.yml.enc にセットします。(Rails5.2以降で可能)

このファイルはエディタで表示すると暗号化された文字列になっていますが、 master.key を使うことで閲覧、編集することができます。この credentials.yml.encmaster.key の関係を理解しておいてください。

次のコマンドでcredentials.yml.encを編集します。ここではエディタをvimに指定しています。

ローカル
$ EDITOR=vim bin/rails credentials:edit

下記のようにdbの項目を追記し、RDS作成時に設定したユーザー名、パスワード、データベースエンドポイントを記述します。

credential.yml.enc(ローカル)
# 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の項があります。そこを下記のように修正します。

database.yml(ローカル)
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します。

Gemfile(ローカル)
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に追記します。

Capfile(ローカル)
  :
# require "capistrano/rails/migrations"
# require "capistrano/passenger"
require 'capistrano/rails'
require 'capistrano/rbenv'
  :

13. デプロイの設定

Capistranoのデプロイ設定を行います。全体的なデプロイの設定を「config/deploy.rb」、本番環境用の設定を「config/deploy/production.rb」に記述します。

config/deploy.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へのキー登録については下記をご参照ください。

config/deploy/production.rb(ローカル)
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の設定を行います。

config/puma/production.rb(ローカル)
# 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
/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
/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タスクを追加しておくと、それも自動で実行してくれます。

config/deploy.rb(ローカル)
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

以上です。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3