AWSでrailsのアプリケーションをデプロイする

AWSでrailsのアプリケーションをデプロイする

はじめに

今回はAmazon Web Services(AWS)を使用して、railsのアプリケーションをデプロイしてみようと思います。この記事ではデプロイの運用の勉強をする目的として書いているので、実際の本番環境として運用するときには方法が異なります。また、説明がかなり長くなってしまうので、railsやgitの環境構築周りのコマンドの説明は端折りながら進めていきます。

AWSの設定

①Cloud9の環境構築

awsのマネジメントコンソールの検索窓にて「cloud9」し、cloud9のサービスに飛んでください。

そのあとに環境を作成というボタンをクリックしましょう。

すると、以下のような画面が出てくると思うので、名前欄に任意の名前を付けて下に進みます。

awsで課金を発生させたくないという人は以下の画像のようにインスタンスタイプでt2.microが選択されていることを確認しましょう。

ここまで確認出来たら、下まで行き、「作成」ボタンを押しましょう。ここはcreateと書いてあるかもしれないです。

次に、git,ruby,railsの環境構築をしていきます。こちらはメインではないので、サクサク行きます。

gitのリモートリポジトリ紐づけ

※$が先頭についているものはターミナル上での操作になります。

$ ssh-keygen
$ cat ~/.ssh/id_rsa.pub

ここでターミナルに出てきたssh-rsaからinternalまでをコピーし、githubにsshキーとして登録しましょう。

$ ssh -T git@github.com

こちらでsshキーの紐づけが確認できれば完了です。git configの設定などはお好みでどうぞ。

rubyのバージョン変更

cloud9にはすでにrubyが入っていますが、今回私はruby 3.1.2というバージョンで開発しているので、こちらに合わせていきます。

$ ruby -v

こちらのコマンドでrubyのバージョンが自分と同じ人はそのまま進めて大丈夫です。

$ rvm get stable
$ rvm install 3.1.2
$ rvm --default use 3.1.2

はい。これでruby 3.1.2をインストール、デフォルトバージョンにすることに成功しました。一応下記のコマンドでバージョンが変わっているか確認しておきましょう。

ruby -v

Rails6系の導入

$ gem install rails -v 6.1.4

nodeのバージョンなどはお好みで入れてしまって大丈夫です。
だいぶざっくりですが、これでcloud9の環境構築はいったん終わりです。

②デプロイ用EC2インスタンスの設定

EC2インスタンスの作成

ここではEC2というAWSが提供する仮想サーバーの設定を行っていきます。
まずはawsマネジメントコンソールの検索窓で「EC2」と検索しましょう。
EC2の画面を開くことができたら下記の画像の場所を押します。

次の画面に進むことができたら以下の手順を実行します。

1.名前には任意の名前を入力
2.アプリケーションおよび OS イメージではAmazon Linuxを選択
3.マシンイメージにはAmazon Linux 2 AMI (HVM) – Kernel 5.10, SSD Volume Type
4.インスタンスタイプにはt2.microを選択
5.キーペアでは新しいキーペアを作成を押す
6.キーペア名は任意の名前、キーペアのタイプはED25519でキーペアを作成
7.キーペアがダウンロードされるので、任意の場所に保存(なくさないように!)
8.ネットワーク設定の右の方にある編集をクリック
9.サブネット項目をcloud9のEC2と同じアベイラビリティーゾーン(AZ)を選択

※EC2のインスタンス一覧からAZを確認可能

10.セキュリティグループを追加を押す
11.タイプはHTTP,ソースタイプは「カスタム」、ソースは「0.0.0.0/0」と「::/0」こちらを入力する
12.インスタンスを起動をクリック

これでデプロイ用のEC2インスタンスを作成することができました。

Cloud9との紐づけ

インスタンスをcloud9と紐づけていきます。手順としては簡単です。
まずは先ほどダウンロードしてきたキーペアをcloud9のhomeディレクトリに置く。

$ mv キーペア名.pem ~/.ssh/

キーペア名には自分のキーペアの名前を入れましょう

$ sudo chmod 600 ~/.ssh/キーペア名.pem

以下のコマンドでサーバーにアクセスする。

$ ssh -i ~/.ssh/キーペア名.pem ec2-user@xx.xx.xx.xx

xx.xx.xx.xxの部分には先ほど作成したEC2インスタンスのパブリックIPアドレスを入力しましょう。インスタンス一覧から見たいインスタンスにチェックを入ると、下に詳細が出てきます。そこのパブリックIPアドレスの部分を入力しましょう。

以下のメッセージが出ると思うので、yesで進めます。

The authenticity of host 'xx.xx.xx.xx (xx.xx.xx.xx)' can't be established.
ECDSA key fingerprint is SHA256:+MxOlUCf7HpfqkE4syIBDBSr0xt6Mq8sl/sS27TT1Mk.
Are you sure you want to continue connecting (yes/no)?

サーバーに「Nginx」をインストール

ここからはサーバーにアクセスした状態とcloud9のターミナルに出た状態を行き来します。
ec2-userから始まっているときはサーバー上で打っているコマンドです。

[ec2-user@ip-xx-xx-xx-xx ~]$ sudo amazon-linux-extras install -y nginx1
[ec2-user@ip-xx-xx-xx-xx ~]$ sudo systemctl enable nginx
[ec2-user@ip-xx-xx-xx-xx ~]$ sudo systemctl start nginx

これでnginxのインストールおよび、サーバーを起動したときにnginxが自動起動する設定、nginxの起動が終了しました。この状態でブラウザの検索窓にパブリックipアドレスを入力して検索してみましょう。
「Welcome to nginx」という表示がされるはずです。
※nginxのコマンドを打った直後だとうまく検索できない可能性があるので、その場合は少し間をおいてみましょう

また、サーバーは使用しないときは停止しておかないと課金が発生するので、インスタンスごと停止するのを忘れないようにしてください。今の状態だとサーバーのパブリックIPアドレスは起動するたびに代わるので、注意しましょう。

③RDSを構築する

RDSを作成する

まずはawsマネジメントコンソールの検索窓で「RDS」と検索しましょう。そしたら上の方に出てくる「データベースの作成」を押しましょう。

1.データベースの作成方法は「標準作成」
2.エンジンのオプションを「MySQL」
3.エンジンバージョンは[MySQL 8.0」から始まるもの
4.テンプレートは無料利用枠を選択
5.DB クラスター識別子は任意の名前
6.マスターユーザー名も任意の名前
7.マスターパスワードの設定と確認(これも任意)
8.インスタンスの設定では以前の世代のクラスを含むをオンにし、db.t2.microを選択
9.ストレージの自動スケーリングを有効にするのチェックを外す
10.「コンピューティングリソース」を「EC2 コンピューティングリソースに接続しない」に設定
11.「パブリックアクセス可能」を「なし」に設定
12.「アベイラビリティーゾーン」にはcloud9と同じものを指定
13.データベースの作成をクリック

これでデータベースの作成が完了しました。

セキュリティグループの変更

1.データベース名をクリックで詳細ページを開く
2.下の接続とセキュリティでVPCセキュリティグループをクリック
3.画像の位置にチェックを入れ、インバウンドルールを押す

4.インバウンドルールを編集をクリック
5.ルールを追加を押し、MYSQL/Auroraを選択し、サーバー用のEC2のプライベートIPアドレスを入力する

EC2からRDSへ接続

1.sshでログイン

$ ssh -i ~/.ssh/キーペア名.pem ec2-user@xx.xx.xx.xx

2.MySQLのソフトウェアをインストール

[ec2-user@ip-xx-xx-xx-xx ~]$ sudo yum -y install mysql

3.mysql -u (マスタユーザ名) -p -h (エンドポイント)でRDSに接続
エンドポイントは先ほど作ったrdsの詳細ページで確認できます。

[ec2-user@ip-xx-xx-xx-xx ~]$ mysql -u root -p -h rds-mysql-server.xxx.ap-northeast-1.rds.amazonaws.com
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.7.22-log MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

これでrdsへの接続が完了しました。

mysql> exit

このコマンドで出ておきましょう。

デプロイ手順

①開発環境の準備

1.自分のアプリケーションをgithubからcloud9にcloneする
2.Gemfileを編集

# バージョンを変える
gem 'puma', '~> 3.11'

# 追加
gem 'dotenv-rails'
group :production do
  gem 'mysql2'
end
gem "net-smtp"
gem "net-pop"
gem "net-imap"

データベースの接続設定で「環境変数」を利用するので、環境変数を管理するGemを追加します。
環境変数とはシステム上で利用できる「変数」のことです。

$ bundle install --without production

4.「.env」ファイルを作成し、下記の内容を保存

DB_USERNAME="RDSの接続ユーザ名"
DB_PASSWORD="RDSのパスワード"
DB_HOST="RDSのエンドポイント名"
DB_DATABASE="データベース名"

「DB_USERNAME」、「DB_PASSWORD」、「DB_HOST」は先ほどrdsで自分が設定、生成されたものを書いてください。
「DB_DATABASE」は自分のrailsのアプリケーション名を書いておきましょう。

5.「.gitignore」ファイルに追記

※ここはセキュリティ上一番重要です
.gitignoreファイルの最終行に以下を追記して、保存してください。

/.env

これで先ほどのrdsの設定がgithubのトラッキングから外れます。

6.config/database.ymlに、データベース(MySQL)へ接続するための設定を記述

production:セクションの記述を編集します。
また、設定情報の一部には、さきほどの.envファイルで設定した環境変数を使用します。
.envファイルで記述した内容が、以下の記述と結びつきを持っています。(<%= ENV[‘DB_DATABASE’] %>は.envファイルに記述したDB_DATABASEに対応しています。)

production:
  <<: *default
  database: <%= ENV['DB_DATABASE'] %>
  adapter: mysql2
  encoding: utf8mb4
  charset: utf8mb4
  collation: utf8mb4_general_ci
  host: <%= ENV['DB_HOST'] %>
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>

7.Pumaを設定

config/puma.rbの最終行に、以下を追加してください。

bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
rails_root = Dir.pwd
# 本番環境のみデーモン起動
if Rails.env.production?
  pidfile File.join(rails_root, 'tmp', 'pids', 'puma.pid')
  state_path File.join(rails_root, 'tmp', 'pids', 'puma.state')
  stdout_redirect(
    File.join(rails_root, 'log', 'puma.log'),
    File.join(rails_root, 'log', 'puma-error.log'),
    true
  )
  daemonize
end

8.Githubへpushする

②本番環境の準備

1.サーバーにログインする

$ ssh -i ~/.ssh/キーペア名.pem ec2-user@xx.xx.xx.xx

2.RDSに接続する

mysql -u (マスタユーザ名) -p -h (エンドポイント)

3.データベースを作成する

mysql> create database アプリケーション名;

作成出来たらexitで出ましょう。

4.ImageMagickをインストールする

今回は開発環境でImageMagickを使用しているので、EC2上にインストールします。

[ec2-user@ip-xx-xx-xx-xx ~]$ sudo yum -y install libpng-devel libjpeg-devel libtiff-devel gcc-c++ git
[ec2-user@ip-xx-xx-xx-xx ~]$ git clone -b 7.1.1-5 --depth 1 https://github.com/ImageMagick/ImageMagick.git ImageMagick-7.1.1-5
[ec2-user@ip-xx-xx-xx-xx ~]$ cd ImageMagick-7.1.1-5
[ec2-user@ip-xx-xx-xx-xx ImageMagick-7.1.1-5]$ ./configure
[ec2-user@ip-xx-xx-xx-xx ImageMagick-7.1.1-5]$ make
[ec2-user@ip-xx-xx-xx-xx ImageMagick-7.1.1-5]$ sudo make install
[ec2-user@ip-xx-xx-xx-xx ImageMagick-7.1.1-5]$ cd

5.rubyをインストールする

EC2にはデフォルトでrubyがインストールされていますが、自分が開発した環境と同じものをダウンロードしましょう。

まずは古いrubyをアンインストールします。

[ec2-user@ip-xx-xx-xx-xx ~]$ sudo yum remove -y ruby*

rbenvのインストールに必要なパッケージをインストールします。

[ec2-user@ip-xx-xx-xx-xx ~]$ sudo yum -y install openssl-devel readline-devel

rbenvをインストールします。

[ec2-user@ip-xx-xx-xx-xx ~]$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
[ec2-user@ip-xx-xx-xx-xx ~]$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
[ec2-user@ip-xx-xx-xx-xx ~]$ sudo ~/.rbenv/plugins/ruby-build/install.sh
[ec2-user@ip-xx-xx-xx-xx ~]$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
[ec2-user@ip-xx-xx-xx-xx ~]$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
[ec2-user@ip-xx-xx-xx-xx ~]$ source ~/.bash_profile

使いたいバージョンのrubyとBundlerをインストールします。

[ec2-user@ip-xx-xx-xx-xx ~]$ rbenv install 3.1.2
[ec2-user@ip-xx-xx-xx-xx ~]$ rbenv global 3.1.2
[ec2-user@ip-xx-xx-xx-xx ~]$ rbenv rehash
[ec2-user@ip-xx-xx-xx-xx ~]$ rbenv exec gem install bundler

少し時間はかかりますがこれでインストールは完了です。バージョンを確認しておきましょう。

[ec2-user@ip-xx-xx-xx-xx ~]$ ruby -v
[ec2-user@ip-xx-xx-xx-xx ~]$ bundle -v

6.Railsをインストールする

Railsをインストールするために必要なパッケージをインストールしていきます。

[ec2-user@ip-xx-xx-xx-xx ~]$ sudo yum -y install patch libyaml-devel zlib zlib-devel libffi-devel make autoconf automake libcurl-devel sqlite-devel mysql-devel

Node.jsをインストールするためのnvmをインストールします。

[ec2-user@ip-xx-xx-xx-xx ~]$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
[ec2-user@ip-xx-xx-xx-xx ~]$ export NVM_DIR="$HOME/.nvm"
[ec2-user@ip-xx-xx-xx-xx ~]$ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ec2-user@ip-xx-xx-xx-xx ~]$ [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

Node.jsをインストールします

[ec2-user@ip-xx-xx-xx-xx ~]$ curl -O https://unofficial-builds.nodejs.org/download/release/v18.17.1/node-v18.17.1-linux-x64-glibc-217.tar.gz
[ec2-user@ip-xx-xx-xx-xx ~]$ tar -xzf node-v18.17.1-linux-x64-glibc-217.tar.gz
[ec2-user@ip-xx-xx-xx-xx ~]$ mkdir -p ~/.nvm/versions/node/v18.17.1-custom
[ec2-user@ip-xx-xx-xx-xx ~]$ mv ~/node-v18.17.1-linux-x64-glibc-217/* ~/.nvm/versions/node/v18.17.1-custom/
[ec2-user@ip-xx-xx-xx-xx ~]$ export PATH=$PATH:~/.nvm/versions/node/v18.17.1-custom/bin/
[ec2-user@ip-xx-xx-xx-xx ~]$ source ~/.bashrc

明示的にインストールしたNode.jsを使用できるようにコマンドを入力します。

[ec2-user@ip-xx-xx-xx-xx ~]$ nvm alias default v18.17.1-custom
[ec2-user@ip-xx-xx-xx-xx ~]$ nvm use v18.17.1-custom

nodeのバージョンを確認しておきましょう。

[ec2-user@ip-xx-xx-xx-xx ~]$ node -v

yarnをインストールします

[ec2-user@ip-xx-xx-xx-xx ~]$ npm install -g yarn

そして最後に本命のrailsをインストールします。今回はバージョン6.1.4を開発で使っていたので、こちらをインストールします。

[ec2-user@ip-xx-xx-xx-xx ~]$ gem install rails -v 6.1.4
[ec2-user@ip-xx-xx-xx-xx ~]$ rails -v

③本番環境へアプリケーションを配置する

この章ではcloud9とEC2を行き来するので注意深く読んでください

1.Cloud9から秘密鍵をEC2サーバーに送る

$ scp -i ~/.ssh/キーペア名.pem ~/.ssh/id_rsa ec2-user@パブリックIPアドレス:.ssh/id_rsa

2.EC2にログインしてgit cloneする

[ec2-user@ip-xx-xx-xx-xx ~]$ git clone GitHubのリポジトリのURL

3.master.keyを生成する

今回はcloud9上にgithubからcloneしてきたアプリを変更しているので、master.keyファイルがありません。
master.keyはとても重要なカギなので、gitでの管理下にはおかれません。なので、githubからcloneしてきたアプリケーションには存在しないということです。master.keyはアプリケーションに必要で本番環境に使うものなので、今から生成していきましょう。

まずはconfig/credentials.yml.encというファイルを削除してください。このファイルはmaster.keyとセットで使うものなので、もとのmaster.keyがない現在使うことができません。
削除することができたら以下のコマンドを打ちます。

$ EDITOR=vim rails credentials:edit

これにより、configディレクトリの下にcredentials.yml.encとmaster.keyのセットが生成されていると思います。

4.master.keyとcredentials.yml.encをアップロードする

先ほど言った通りgithubからcloneしてきたrailsのアプリケーションにはmaster.keyがないため、先ほど生成したmaster.keyとcredentials.yml.encをEC2上のアプリケーションにアップロードしていきます。

$ scp -i ~/.ssh/キーペア名.pem config/master.key ec2-user@IPアドレス:GitHubのリポジトリ名/config
$ scp -i ~/.ssh/キーペア名.pem config/credentials.yml.enc ec2-user@IPアドレス:GitHubのリポジトリ名/config

これでmaster.keyとcredentials.yml.encをEC2上のアプリケーションにコピーできました。

5.EC2上でサーバー起動前の準備をする

[ec2-user@ip-xx-xx-xx-xx ~]$ cd GitHubのリポジトリ名
[ec2-user@ip-xx-xx-xx-xx GitHubのリポジトリ名]$ bundle install --path vendor/bundle --without test development
[ec2-user@ip-xx-xx-xx-xx GitHubのリポジトリ名]$ echo 'export NODE_OPTIONS=--openssl-legacy-provider' >> ~/.bashrc
[ec2-user@ip-xx-xx-xx-xx GitHubのリポジトリ名]$ source ~/.bashrc
[ec2-user@ip-xx-xx-xx-xx GitHubのリポジトリ名]$ bundle exec rails assets:precompile RAILS_ENV=production
[ec2-user@ip-xx-xx-xx-xx GitHubのリポジトリ名]$ bundle exec rails db:create RAILS_ENV=production
[ec2-user@ip-xx-xx-xx-xx GitHubのリポジトリ名]$ bundle exec rails db:migrate RAILS_ENV=production

④Webサーバーの設定をする

1.Nginxの設定ファイルを編集する

sudoでviを実行してファイルを開き、/etc/nginx/nginx.confを編集します。

[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ sudo vi /etc/nginx/nginx.conf

user nginx;の行をコメントアウトして、下の行にuser ec2-user;を記述します。

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

#user nginx;
user ec2-user;

worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

次に、/etc/nginx/conf.d/アプリケーション名.confを作成します。下記のコマンドを入力してください。

[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ sudo vi /etc/nginx/conf.d/アプリケーション名.conf

viでファイルを編集できるようにしたら、以下の記述を書きましょう。

upstream puma {
  server unix:///home/ec2-user/アプリケーション名/tmp/sockets/puma.sock;
}
server {
  listen       80;
  server_name  EC2のパブリックIPv4アドレスもしくはドメイン取得している方はドメイン名を設定;
  root /home/ec2-user/アプリケーション名/public;
  access_log  /var/log/nginx/access.log  main;
  error_log /var/log/nginx/error.log;
  sendfile            on;
  tcp_nopush          on;
  tcp_nodelay         on; 
  keepalive_timeout   65;
  types_hash_max_size 2048;
  client_max_body_size 100M;
  include             /etc/nginx/mime.types;

  location / {
    proxy_pass http://puma;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_redirect off;
    proxy_connect_timeout 30;
  }

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    root /home/ec2-user/アプリケーション名/public;
  }

  location ^~ /packs/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    root /home/ec2-user/アプリケーション名/public;
  }
}

日本語が書いてある場所は自分の環境によって書き換えてください。

2.設定ファイルの構文チェック

[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ sudo nginx -t

以下のように出れば成功です。

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

3./var/lib/nginxの権限をnginxの実行ユーザーにする

[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ sudo chown -R ec2-user /var/lib/nginx

4.ウェブサーバーを再起動する

nginxの設定を反映させるためにウェブサーバーを再起動します。

[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ sudo systemctl restart nginx

5.アプリケーションサーバーを起動する

[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ rails s -e production

起動できたら、ブラウザにURLを入力して確認しましょう。URLには、IPv4 パブリック IPを入力します。
ただ、これには時間がかかる場合があります。「応答時間が長すぎます」などのエラーが出たら少し時間をおいてもう一度確認してみましょう。

さいごに

今回はawsでrailsアプリケーションをデプロイする手順を書いてみました。今回は完全無料でデプロイしてみたいと思ってやっているので、ここに書いた方法だとインスタンスを起動し直すたびにIPアドレスが変わったりで全然実際の運用の環境とは違いますが、大まかな流れとして覚えておいても損はないかなと思います。では今回はここらへんで失礼します。ここまで読んでいただきありがとうございました。