EC2上でRailsアプリケーションにDockerを導入する(Rails、Nginx、RDS)

___
※ DockerでRailsの環境構築をする方法に関して新しい記事を書いたので、下記を参照ください。 (2021/1/21更新)

- <a href="https://qiita.com/Yusuke_Hoirta/items/3a50d066af3bafbb8641">Dockerを用いてRuby on Railsの環境構築をする方法( Docker初学者向け )</a>

___

前回の記事（<a href="https://qiita.com/somagawa/items/18dae771163a02a53a37">開発環境において既存のRailsアプリにDockerを導入する方法(Rails、nginx、mysql)</a>）で開発環境において、既存のRailsアプリケーションにDockerを導入する方法をご紹介しました。
今回は本番環境においてDockerを導入する方法をご紹介します。

# 前提
開発環境ではRails、nginx、MySQLをコンテナ化しましたが、本番環境においてデータベースであるMySQLをコンテナ化するのは、あまり良くありません。（消える可能性があるため）
そのため、今回はAWSのサービスであるRDSのMySQLを利用します。


# 環境
- Mac OS
- Ruby2.5.7
- Rails5.2.4
- mysql5.7
- nginx1.15.8

# 事前準備
- ローカル環境のご自身のRailsアプリケーションにDockerが導入されていること。
(<a href="https://qiita.com/somagawa/items/18dae771163a02a53a37">開発環境において既存のRailsアプリにDockerを導入する方法(Rails、nginx、mysql)</a>)
- Dockerを利用しないで、EC2においてデプロイができるまでの環境設定ができていること。
- EC2上にDockerとdocker-composeがインストールできていること。

# ファイル構成

```
myapp
  |-- app
  |-- bin
  |-- config
  |-- containers
    |-- nginx
      |-- Dockerfile
      |-- nginx.conf
  |-- db
  |-- lib
  |-- log
  |-- public
  |-- storage
  |-- test
  |-- tmp
  |-- vendor
  |-- .env
  |-- .gitignore
  |-- config.ru
  |-- docker-compose.yml
  |-- Dockerfile
  |-- Gemfile
  |-- Gemfile.lock
  |-- package.json
  |-- Rakefile
  |-- README.md
```
開発環境でDockerを導入しているRailsアプリケーションのファイルを一部編集して、本番環境用とします。
myappはご自身のアプリケーション名に変えてください。

# Gemfileを編集
環境変数を利用するので、環境変数を管理するgemをインストールします。

- Gemfileに以下を追加。

```ruby:Gemfile
gem 'dotenv-rails'
```
bundle installを実行。

```
$ bundle install
```

# .envを作成
.envを作成し、データベース情報の環境変数にする設定を行います。
""内はご自身のものを記載してください。

```html:.env
DB_USERNAME="RDSの接続ユーザ名"
DB_PASSWORD="RDSのパスワード"
DB_HOST="RDSのエンドポイント名"
DB_DATABASE="myapp"
```

# .gitignoreを編集
.gitignoreに記述することでgithubによる管理がされなくなります。

- .gitignoreに以下を追加。

```text:.gitignore
/.env
```

# database.ymlを編集
- production:配下を編集。

```yml:database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch('MYSQL_USER') { 'root' } %>
  password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %>
  host: db

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

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'] %>
```

# docker-compose.ymlの編集
- db:配下をコメントアウト。
- app: の command: に -e production を追加。
- volumes: の mysql-data: をコメントアウト。

```yml:docker-compose.yml
version: '3'
services:
  # db:
    # image: mysql:5.7
    # environment:
      # MYSQL_ROOT_PASSWORD: password
      # MYSQL_USER: user
      # MYSQL_PASSWORD: 1234
      # MYSQL_DATABASE: myapp_db
    # volumes:
      # - mysql-data:/var/lib/mysql
    # ports:
      # - "4306:3306"

  app:
    build: .
    command: bundle exec puma -C config/puma.rb -e production
    volumes:
      - .:/myapp
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
      - log-data:/myapp/log

  web:
    build:
      context: containers/nginx
    volumes:
      - public-data:/myapp/public
      - tmp-data:/myapp/tmp
    ports:
      - 80:80

volumes:
  # mysql-data:
  public-data:
  tmp-data:
  log-data:
```

# nginx.confを編集
- nginx.confのserver_nameを編集。

server_name の　xx.xxx.xxx.x にはご自身のIPアドレスもしくはドメインを発行している場合はドメイン名を記入してください。

```text:nginx.conf
upstream myapp {
  server unix:///myapp/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name xx.xxx.xxx.x;

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  root /myapp/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @myapp;
  keepalive_timeout 5;

  location @myapp {
    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://myapp;
  }
}
```
これでファイルの作成、編集は完了です。

# githubへpush
```
$ git add -A
$ git commit -m "deploy setting"
$ git push origin HEAD
```

# Railsアプリケーションをデプロイする
EC2にログインします。
xx.xxx.xxx.x はご自身のパブリックIPを記入してください。

```
$ ssh -i ~/.ssh/practice-aws.pem ec2-user@52.193.217.0

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

```
githubからアプリケーションを取得

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

# githubで管理されないファイルをアップロード
master.key と .env は.gitignoreに記載していたため、githubにアップロードされていません。
そのため、EC2に直接アップロードします。

<b>EC2からログアウト</b>し、アプリケーションの<b>configディレクトリに移動</b>し、以下のコマンドを実行。
my.pemはご自身のキーペアを記入してください。
xx.xxx.xxx.x はご自身のパブリックIPを記入してください。

```
$ scp -i ~/.ssh/my.pem master.key ec2-user@xx.xx.xxx.xxx:myapp/config
master.key                                          100%   32     1.2KB/s   00:00   
```
アプリケーション直下に移動し、以下のコマンドを実行。

```
$ scp -i ~/.ssh/my.pem .env ec2-user@xx.xx.xxx.xxx:myapp/
.env                                                100%  134     5.7KB/s   00:00
```

# イメージのビルド
イメージのビルドをします。

```
[ec2-user@ip-xxx-xx-xx-xxx]$ cd myapp
[ec2-user@ip-xxx-xx-xx-xxx myapp]$ docker-compose build
```

# サーバー起動前の準備
```
[ec2-user@ip-xxx-xx-xx-xxx myapp]$ docker-compose run app rails assets:precompile RAILS_ENV=production
```

# コンテナの起動
EC2にログインし、コンテナを起動。

```
[ec2-user@ip-xxx-xx-xx-xxx myapp]$ docker-compose up -d
```

# データベースの作成、マイグレーションファイルの読み込み
最後に以下のコマンドでデータベースの作成とマイグレーションファイルの読み込みをします。

```
[ec2-user@ip-xxx-xx-xx-xxx myapp]$ docker-compose exec app rails db:create db:migrate RAILS_ENV=production
```
パブリックIPにアクセスして、正しく表示されればOKです。

# 参考記事
- <a href="https://qiita.com/eighty8/items/0288ab9c127ddb683315">Docker + Rails + Puma + Nginx + MySQL</a>
- <a href="https://qiita.com/azul915/items/5b7063cbc80192343fc0">丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)</a>
- <a href="https://qiita.com/at-946/items/1e8acea19cc0b9f31b98">無料！かつ最短？で Ruby on Rails on Docker on AWS のアプリを公開するぞ。</a>