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

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

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

|  | タイトル |
|:-:|:--|
| 1  |  [ローカル環境のRailsアプリをDockerコンテナ化](https://qiita.com/sho_U/items/a1b5e4ddf13f3c42a722) |
| 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にアップロードする  |

#DockerコンテナをAWSにアップロードします。
　この項目では、かなり苦しめられました。ngixやpuma、RDSなど接続しなくてはいけないものが多々あり、また、AWS内にコンテナを構築することにより今、自分がどこにいるのか、よくわからなくなる状態に陥ることがありました。
　この記事通りに、行ってもうまくいかないかもしれませんが、少しでもどなたかのお力になれればと思います。
　自分はできれば、再びあのような思いをしたく無いので忘れないうちに記事として残しておきました。

作成したAWSインスタンスにローカルdockerコンテナをアップロードしていきます。

##コンテナ内での環境変数を設定します。
現状、database.ymlを確認すると

```database.yml
  username: root
  password: password
  host: db
```
このように、セキュアな情報がハードコーディングされています。
このままではgithubのコードから漏洩する危険があるので、本番環境のコンテナ内で環境変数を用いてセキュアな情報を設定します。

環境変数については、参考までに下記をご覧下さい。
[環境変数について]
(https://qiita.com/sho_U/items/cd5fc4d4d76b65b92d23)

環境変数を利用するために、dotenv-railsというgemをインストールします。
Gemfileに以下を追記します。

```Gemfile.
gem 'dotenv-rails'
```
dotenv-railsをインストールすることにより、「.env」ファイルに記載された環境変数をdockerコンテナ内で、下記のような記述で取り出せる様になります。

```
ENV['DATABASE_PASSWORD']
```

また、.envファイルをgithubに上げてしまうと元も子も無いので、gitignoreに追記します。

```gitignore
.env
```

.envを下記の様に記載してアプリ直下に配置します。

```.env
DB_USERNAME=root
DB_PASSWORD=gakjadfmoaeur
DB_HOST=fito2-db-instance.〇〇〇〇〇〇.ap-northeast-1.rds.amazonaws.com
DB_DATABASE=fitO2_db
```
DB_HOSTはRDSのエンドポイントです。
AWSのRDSダッシュボードのデーターベースをクリックし、一覧から該当のRDSを選択すると確認できます。

##database.ymlの修正

database.ymlに下記を追加して、本番環境は環境変数から値を読み込むようにします。

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

##nginx.confの修正

以下の部分を本番用に修正します。

```nginx.conf
server {
  listen 80;
# =========ローカルと本番切り替え===========
  server_name 固定IP;
  # server_name localhost;
# ======================================
```

##docker-compose.ymlの修正

```docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
# =========ローカルと本番切り替え===========
    command: bundle exec puma -C config/puma.rb -e production
    # 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コンテナは本番環境ではRDSを使用するので不要のため、コメントアウト
**(appコンテナのdepend onもまとめてコメントアウトします)**
・command のrails s に -e production を追記して、本番環境でサーバー立ち上げるようにした。


##AWSインスタンス上にdockerコンテナを構築する。

今一度、AWSインスタンス上にdockerコンテナを構築するまでの流れを整理します。

今、現状ローカルでは、下記のようにfitO2というファイルを元に、下記の様なdockerコンテナをbuildできる状態でした。
![IMG_E6E1E78616D4-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/5c26b299-617b-f411-7bfb-0dccf14059c9.jpeg)


そして、fitO2というファイルを書き換えて、以下の様なコンテナが作成されるように修正しました。（DBコンテナ削除）
![IMG_8878B35F0D0C-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/b44bd4d2-7f32-d155-7e18-36cdfe3692b1.jpeg)

その、fitO2をgithubにpushします。そして、AWS側からclone(2回目以降はpull)します。
![IMG_5390174B203B-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/6d2833da-6084-3d49-f664-126048085775.jpeg)
cloneしたfitO2を元に、AWS内でbuildしてコンテナを構築し、AWS内に作成しているRDSと接続します。
![IMG_025BB67DF9F9-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/4b3fb851-ea68-028b-6808-6cdf04904eae.jpeg)

通信の流れはオレンジの矢印となります。

##githubへプッシュ
まずは、修正したファイルをコミットしてgithubへpushします。

##AWSにdockerをインストール

ssh接続でAWSにログインし、dockerをインストールします。

```
sudo yum install -y docker
　　//インストール

sudo service docker start
　　//docker起動

sudo usermod -G docker ec2-user
　　//ec2-userに権限付与

exit
　　//ログアウト
　　//再度sshでログイン

docker info
```
下記の様な表示がされたらオッケーです。

```
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.13-ce
```

```
sudo chkconfig docker on
//EC2起動時にDockerを自動で立ち上げる
```
docker-composeをインストールします。

```
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

docker-compose -v

docker-compose version 1.24.0, build 0aa59064
  //上記の様にバージョンが表示されたら成功

  //Permission denied となる場合は
sudo chmod +x /usr/local/bin/docker-compose
　//でdocker-composeへ実行権限を付与したあとにもう一度 docker-compose -v を実行するとversionが表示されます。
```

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

```
sudo yum install -y git
```
秘密鍵を作成します。(質問は全てエンター）

```
ssh-keygen -t rsa -b 4096
```
作成した秘密鍵を表示し、コピーします。

```
cat ~/.ssh/id_rsa.pub
```
https://github.com/settings/keys
こちらにアクセスします。

右上の「new SSH key」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/0ad74ade-bde7-c296-455b-94d6aa7857c6.png)

titleを適宜入力し、keyのところに先ほどコピーした文字列を貼り付けます。
（ssh-rsa~から含めます）

```
ssh -T git@github.com
```
上記を打ち込んで、途中yesと入力し、下記の様に表示されればAWSとgithubの認証が成立しました。

```
Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.
```
以後、AWSインスタンス側から自身のgithubに対し、pull等ができる様になります。

githubからcloneします。（URLはリポジトリを表示したときのURL）

```
cd /
//ルート直下に移動します。homeディレクトリでコンテナを展開すると、pumaとnginxの連携でエラーが出る場合がありますl。puma.sockの読み取りエラー
```

```
sudo git clone https://github.com/〇〇〇〇〇〇/〇〇〇〇〇〇
```
```
ls
//lsと打って、ディレクトリがあるか確認する。
```
今、gitignoreに記載したファイル(.env master.key)は含まれていません。そこで、ssh通信を用いてローカルからAWSに直接ファイルを転送します。

```
exit
　//一旦ログアウトして、ローカルのfitO2ファイルに移動

sudo scp -i ~/.ssh/fitO2_key.pem .env ec2-user@固定IP:/home/ec2-user/

sudo scp -i ~/.ssh/fitO2_key.pem config/master.key ec2user@固定IP:/home/ec2-user

  //scpコマンドを用いて、AWSに.envを転送します。　.env　のように転送したファイルが表示されたらオッケー。
  //権限の関係で一旦、ホームディレクトリに転送します。
```
再度、ログイン。

```
cd
ls -a
```
ホームディレクトリに移動して.envとmaster.keyが存在していたら問題ない。
.envとmaster.keyを移動させる。

```
sudo mv .env /fitO2
sudo mv master.key /fitO2/config
```

念のため移動してるか確認

```
ls -a  /fitO2/
ls -a  /fitO2/config
```

##コンテナの起動

```
cd /fitO2

docker-compose build
//コンテナを作成します。
(Permition deniedになった場合は、sudo chmod 777 /usr/local/bin/docker-compose
を実行します。）

docker network create fitO2-network
//ネットワークを作成します。

docker-compose run app rails assets:precompile RAILS_ENV=production
//プリコンパイルを実施

docker-compose up
//コンテナを起動します。
```
下記のように表示されていれば問題なく起動しています。

```
Creating fito2_app_1 ... done
Creating fito2_web_1 ... done
Attaching to fito2_app_1, fito2_web_1
app_1  | Puma starting in single mode...
app_1  | * Version 3.12.6 (ruby 2.5.1-p57), codename: Llamas in Pajamas
app_1  | * Min threads: 5, max threads: 5
app_1  | * Environment: production
app_1  | * Listening on tcp://0.0.0.0:3000
app_1  | * Listening on unix:///fitO2/tmp/sockets/puma.sock
app_1  | Use Ctrl-C to stop
```
別タブを開いて、AWSにログインします。



###データベースの作成

```
docker-compose exec app rails db:create db:migrate RAILS_ENV=production

docker-compose exec app rails db:seed RAILS_ENV=production
//(必要に応じて）
```
以上で、http://固定IPにアクセスした場合、正しく表示されるはずです。

##RDSのデーターベース確認方法

#dockerコンテナにログインし、mysqlを起動させます。

```
docker ps
//コンテナIDを調べます。
```

NAMESがfito2_app_1の方のCONTAINER IDをコピーします。

```
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
c5ec64f0ea76        fito2_web           "/bin/sh -c '/usr/sb…"   5 minutes ago       Up 5 minutes        0.0.0.0:80->80/tcp   fito2_web_1
442b9ddb3a20        fito2_app           "bundle exec puma -C…"   5 minutes ago       Up 5 minutes                             fito2_app_1
```
コンテナにログインします

```
docker exec -it 442b9ddb3a20 bash
```

mysqlを起動させます。

```
service mysql start
```

```
mysql -u root -h RDSのエンドポイント -p
//パスワードを入力してログイン
```
セキュリティーグループで制限んしているので、作成したEC２コンテナからしかアクセスできません。

ローカルから試してみてください。

以上となります。

###参考
[EC2上でRailsアプリケーションにDockerを導入する(Rails、Nginx、RDS)](https://qiita.com/Yusuke_Hoirta/items/959f91a61ac1e607c0b1)
[開発環境において既存のRailsアプリにDockerを導入する方法(Rails、nginx、mysql)]
(https://qiita.com/Yusuke_Hoirta/items/18dae771163a02a53a37)
[無料！かつ最短？で Ruby on Rails on Docker on AWS のアプリを公開するぞ。]
(https://qiita.com/at-946/items/1e8acea19cc0b9f31b98)
[【画像付きで丁寧に解説】AWS(EC2)にRailsアプリをイチから上げる方法【その1〜ネットワーク,RDS環境設定編〜】](https://qiita.com/Yuki_Nagaoka/items/975b7598806d6ae0c0b2)
[Nginx + Rails (Puma) on Docker のいくつかの実用パターン](https://qiita.com/na-o-ys/items/1a863419e1f6c3063ace)
[Docker + Rails + Puma + Nginx + MySQL]
(https://qiita.com/eighty8/items/0288ab9c127ddb683315)