【Rails AWS Docker】既存Ruby on Rails + MySQLアプリをDockerで構築し、AWSにデプロイする(1)

ポートフォリをとして作ったRuby on RailsアプリをDockerコンテナ化し本番環境をAWSで構築するまでの道のりです。
ポートフォリオ自体はこちらとなります。
[【ポートフォリオ】転職活動時に作成したポートフォリオの概要（テッ◯キャンプ）]
(https://qiita.com/sho_U/items/058e590325ee6833abb0)

かなり苦しめられたので、どなたかのお役に立てれば。

|  | タイトル |
|:-:|:--|
| 1  |  ローカル環境のRailsアプリをDockerコンテナ化 |
| 2  | [AWSにVPCを作成する。パブリックサブネットを作成する](https://qiita.com/sho_U/items/9cdd37fd8c34c677d042)|
| 3 | [プライベートサブネットを作成する](https://qiita.com/sho_U/items/95c25df53a7e1fd20efd)  |
| 4 | [EC2インスタンスを作成する](https://qiita.com/sho_U/items/cb268b774f60cb01c226) |
| 5  | [RDSを作成する](https://qiita.com/sho_U/items/4e5431add35d9318865d)  |
|  6 | [DockerコンテナをAWSにアップロードする](https://qiita.com/sho_U/items/5ef6693f7ae8f1c27bb7) |

参考にさせていただいた記事は、(6)の末尾に記載しています。

#ローカル環境のRailsアプリをDockerコンテナ化


###Dockerコンテナ環境構成（ローカル版）
![IMG_CE2774B27B97-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/03f0e153-22d1-702f-7181-a96f6447538f.jpeg)

構成は上記です。
webサーバーとしてnginxを配置します。
appサーバーはpumaを設置します。



#まず既存のRailsアプリをコンテナ化します。

##前提
AWSにアカウント作成済
docker hubにアカウント作成済
docker インストール済
ローカル環境で動作するRailsアプリ

##構築
※fitO2の部分は、ご自身のアプリ名に変更してください。

現状のアプリのフォルダ構成に、下記のファイルを追加します。

```
docker-compose.yml

Dockerfile

nginx_docker
  ├── Dockerfile
  └── nginx.conf

config
  └── puma.rb

```

```docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
    command: bundle exec puma -C config/puma.rb

    volumes:
      - .:/fitO2
      - public-data:/fitO2/public
      - tmp-data:/fitO2/tmp
      - log-data:/fitO2/log
    networks:
      - fitO2-network
    depends_on:
      - db

  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: fitO2_development
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - fitO2-network

  web:
    build:
      context: ./nginx_docker
    volumes:
      - public-data:/fitO2/public
      - tmp-data:/fitO2/tmp
    ports:
      - 80:80
    depends_on:
      - app
    networks:
      - fitO2-network
      
volumes:
  public-data:
  tmp-data:
  log-data:
  db-data:

networks:
  fitO2-network:
    external: true

```
###簡単な説明
**dbコンテナ**
image　でdockerhubからmysql:5.7をプルします。
ports　でホスト側の3306とコンテナ側の3306ポートを接続します。
networks　でappコンテナ側と共通のネットワークfitO2-networkを利用します。

**appコンテナ**
build　でDockerfileのディレクトリ（コンテキスト）を指定して、Dockerfileからコンテナを作成します。
volumes　で、ホスト側のdocker-compose.ymlが存在しているディレクトリと、コンテナ側の/fitO2をマウント（共通化）しています。
command　で設定ファイルを指定してpuma（アプリケーションサーバー）を立ち上げています。
ports　でホスト側の3000とコンテナ側の3000ポートを接続します。
depends_on　でappコンテナが生成されてから、実行されるように指定しています。
networks　でdbコンテナ側と共通のネットワークfitO2-networkを利用します。

**webコンテナ**
build で./nginx_dockerがあるディレクトリ（コンテキスト）を指定して、Dockerfileからコンテナを作成します。
depends_on　でappコンテナが生成されてから、実行されるように指定しています。


**networks**　でfitO2-networkを設定しています。

```fitO2/Dockerfile.
FROM ruby:2.5.1

RUN apt-get update -qq && \
  apt-get install -y build-essential \
  nodejs\
  mysql-server\
  mysql-client

WORKDIR /fitO2

COPY Gemfile /fitO2/Gemfile
COPY Gemfile.lock /fitO2/Gemfile.lock

RUN gem install bundler
RUN bundle install

RUN mkdir -p tmp/sockets
```
###簡単な説明
FROM　でruby:2.5.1 イメージをdocker hubからインストールします。
1回目のRUN　で、必要なパッケージをインストールしています。
WORKDIR　で作業ディレクトリを/fitO2に設定しています。
COPYで　ホスト側のgemfileとgemfile.lockをコンテナの/fitOディレクトリにコピーしています。
2回目のRUN　でbundlerをインストールします。
3回目のRUN　でgemfileからパッケージをインストールします。
4回目のRUN ソケットファイルを作成しています。

```fitO2/nginx_docker/Dockerfile.
FROM nginx:1.15.8

RUN rm -f /etc/nginx/conf.d/*

ADD nginx.conf /etc/nginx/conf.d/fitO2.conf

# ビルド完了後にNginxを起動
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
```
###簡単な説明
FROM でnginx:1.15.8 イメージをdocker hubからインストールします。
RUN　でインクルード用のディレクトリ内を削除してます。
ADD　でNginxの設定ファイルをコンテナにコピーしてます。
CMD  でビルド完了後にNginxを起動するようにしてます。

```fitO2/nginx_docker/nginx.conf

upstream fitO2 {
  server unix:///fitO2/tmp/sockets/puma.sock;
}

server {
  listen 80;
# =========ローカルと本番切り替え===========
  # server_name ◯◯◯.◯◯◯.◯◯◯.◯◯◯;
  server_name localhost;
# ======================================

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

  root /fitO2/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 @fitO2;
  keepalive_timeout 5;

  location @fitO2 {
    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://fitO2;
  }
}
```
nginxの設定ファイルです。
ローカル環境の場合は、server_name をlocalhostにします。

```config/puma.rb
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart

app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"

stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true
```
pumaの設定ファイルです。
bind "unix://#{app_root}/tmp/sockets/puma.sock"の部分は、nginx.confのserverと一致するようにしなければなりません。

参考

```config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
# PasswordとUsernameはdocker-compose.ymlと合わせます
  username: root
  password: password
  host: db

development:
  <<: *default
  database: fitO2_development

test:
  <<: *default
  database: fitO2_test
```



##コンテナ作成、起動

アプリのディレクトリに移動します。

コンテナを作成します。

```
docker-compose build
```

ネットワークを作成します。

```
docker network create fitO2-network
```

コンテナを起動します。

```
docker-compose up
```
初回はデーターベースの初期化を行います。
ターミナルを別タブで開き、アプリ直下に移動して下記コマンドをうちます。

```
docker-compose exec app rails db:create 
docker-compose exec app rails db:migrate
docker-compose exec app rails db:seed (シーダーがなければ不要)
```
うまくいかなかった場合、試行錯誤した場合は中途半端にシーダーが入ってしまって、バリデーションの関係で弾かれる場合があるので、一度下記の様にデーターベースを削除してから再度上記コマンドを実行してください。

```
docker-compose exec app rails db:drop
```

http://localhost

にアクセスすると、サイトにアクセスすることができます。

エラーがー生じた際は、docker-compose upターミナルにログが出ていますので、確認してください。

とりあえず既存のアプリをDockerコンテナ化できました。

次回(2)へ続く
[AWSにVPCを作成する。パブリックサブネットを作成する。](https://qiita.com/sho_U/items/9cdd37fd8c34c677d042)