もう逃げない。基礎から学ぶDocker入門 / Docker上に構築したRailsをHeroku（本番環境）にデプロイ（公開）する（9/9）

## はじめに

今まで、全然理解できていなくて逃げてたDockerに関して、しっかり理解していこうと思います。

https://www.docker.com/

コレまで、便利なんだろうなと思いながらも、逃げてました。

なので、開発環境では使いこなせるスキルにまでは理解したいと思います。

あと、暗記してたDockerコマンドを１つ１つ理解していきます。

以下のような順番で勉強していきます。

- [Dockerの概要（1/9）](https://qiita.com/ryosuketter/items/d7833182dced67713d27)
- [Dockerの基本操作（イメージの作成, コンテナの起動, 停止, 削除）（2/9）
](https://qiita.com/ryosuketter/items/c53352f1143366d8b9a9)
- [Dockerの基本操作（ログの出力, コンテナの中でプロセスを実行する方法, 使用していない Docker オブジェクトの削除）（3/9）](https://qiita.com/ryosuketter/items/5fd73b7311175a691dfe)
- [Dockerfileを使用したサーバー構築（座学編）（4/9）](https://qiita.com/ryosuketter/items/d9c3420be7da586225e8)
- [Dockerfileを使用したサーバー構築（実践編）（5/9）](https://qiita.com/ryosuketter/items/716a4c5e49795d494600)
- [Docker Composeの概要（座学編）（6/9）](https://qiita.com/ryosuketter/items/104a4eb38f8824eb6de9)
- [Docker Composeのよく使う基本操作（7/9）](https://qiita.com/ryosuketter/items/8bbd2c60392f443cfe23)
- [Docker Composeを使ってRailsの環境を構築する（8/9）](https://qiita.com/ryosuketter/items/91cd107794c1cbe358c6)
- [Docker上に構築したRailsをHeroku（本番環境）にデプロイ（公開）する（9/9）](https://qiita.com/ryosuketter/items/e3e68ce6ec572dc8905e) :point_left_tone1: 今ここ

### 本番環境はHerokuを使う

今回はHeroku上に、Dockerコンテナを起動させて、Webアプリケーションを公開していきます。

![スクリーンショット 2021-09-26 19.57.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/da19165e-e8a2-d8dc-de26-ab54d805dd0c.png)

HerokuはサーバやOSやミドルウェアを自動で構築・管理してくれるサービスです。

https://jp.heroku.com/

以前の記事で作成したRailsのアプリをHeroku上に本番公開していきます。

https://qiita.com/ryosuketter/items/91cd107794c1cbe358c6

### Docker上に構築したRailsをHeroku（本番環境）にデプロイ（公開）するまでの流れ

- 準備
- Herokuにログイン
- Herokuアプリを作成
- HerokuにMySQLを追加し設定する
- Dockerfileを開発環境用と本番用に用意
- Dockerイメージをビルド・リリース

### 準備

Herokuのログイン（もしくはアカウント登録）とDBはMySQLを使うので無料範囲ではありますが、クレカを紐づける必要があります。

続いて、Heroku CLIのインストールをしておきます。

https://devcenter.heroku.com/ja/articles/heroku-cli

### Herokuにログイン

ローカルのターミナルからHerokuにログインできるようにしておきます。

```bash
heroku login
```

ブラウザ経由でログインが完了。

![スクリーンショット 2021-09-26 21.33.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/1d98d631-c6e2-fb5f-51c2-298aad39eabf.png)

続いて、Herokuコンテナレジストリにログインします。

```bash
heroku container:login

Login Succeeded
```

`Succeeded`でたらOKです。

### Herokuアプリを作成

続いて、Herokuアプリ、Herokuは運用したいサービスをアプリという単位で管理しています。

```bash
heroku create rails-docker-ryosuketter

https://rails-docker-ryosuketter.herokuapp.com/ | https://git.heroku.com/rails-docker-ryosuketter.git
```

コレで完成です。

### HerokuにMySQLを追加し設定する

Herokuでは、DBはアドオンという形式で追加できます。

その中でもMySQLの場合はほとんどが有料ですが`cleardb`アドオンの`ignite`というプランはタダなのでそれを使います。

:::note warn
注意
igniteプランのMySQLのバージョンは5系
しかしコレまでの開発環境ではMySQLは8系で作ってました
本当は揃えた方がいいですが、今回はバージョン違いで困らないので、バージョンは揃えません
:::

アドオンを追加します。

追加のコマンド

```bash
heroku addons:create cleardb:<プラン名> -a <アプリ名>
```

実際のコマンド

```bash
heroku addons:create cleardb:ignite -a rails-docker-ryosuketter

Creating cleardb:ignite on ⬢ rails-docker-ryosuketter... free
Created cleardb-cylindrical-02285 as CLEARDB_DATABASE_URL
Use heroku addons:docs cleardb to view documentation
```

コレで無事アドオンを追加できました。

次に、DBの設定をしておきます。

本番環境のRailsの接続先を変えます。

環境によって変えたいので、環境変数にして渡すようにします。

before

```yml
production:
  <<: *default
  database: app_production
  username: app
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>
```

after

```yml:src/config/database.yml
...

production:
  <<: *default
  database: <%= ENV['APP_DATABASE'] %>
  username: <%= ENV['APP_DATABASE_USERNAME'] %>
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>
  host: <%= ENV['APP_DATABASE_HOST'] %>
```

hostも追加されていますね。これで、環境変数の設定が完了しました。

あとは、Herokuに環境変数を渡せば接続できると思います。

DBの接続先情報はHerokuで確認できます。

```bash
heroku config -a rails-docker-ryosuketter

=== rails-docker-ryosuketter Config Vars
CLEARDB_DATABASE_URL: mysql://b86d7f293af671:3f7958e7@us-cdbr-east-04.cleardb.com/heroku_b04f71f6e232c42?reconnect=true
```

herokuにDBの情報を登録していきます。

```bash
$ heroku config:add APP_DATABASE='heroku_b04f71f6e232c42' -a rails-docker-ryosuketter
Setting APP_DATABASE and restarting ⬢ rails-docker-ryosuketter... done, v5
APP_DATABASE: heroku_b04f71f6e232c42

$ heroku config:add APP_DATABASE_USERNAME='b86d7f293af671' -a rails-docker-ryosuketter
Setting APP_DATABASE_USERNAME and restarting ⬢ rails-docker-ryosuketter... done, v6
APP_DATABASE_USERNAME: b86d7f293af671

$ heroku config:add APP_DATABASE_PASSWORD='3f7958e7' -a rails-docker-ryosuketter
Setting APP_DATABASE_PASSWORD and restarting ⬢ rails-docker-ryosuketter... done, v7
APP_DATABASE_PASSWORD: 3f7958e7

$ heroku config:add APP_DATABASE_HOST='us-cdbr-east-04.cleardb.com' -a rails-docker-ryosuketter
Setting APP_DATABASE_HOST and restarting ⬢ rails-docker-ryosuketter... done, v8
APP_DATABASE_HOST: us-cdbr-east-04.cleardb.com
```

環境変数が設定されているか確認

```bash
heroku config -a rails-docker-ryosuketter

=== rails-docker-ryosuketter Config Vars
APP_DATABASE:          heroku_b04f71f6e232c42
APP_DATABASE_HOST:     us-cdbr-east-04.cleardb.com
APP_DATABASE_PASSWORD: 3f7958e7
APP_DATABASE_USERNAME: b86d7f293af671
CLEARDB_DATABASE_URL:  mysql://b86d7f293af671:3f7958e7@us-cdbr-east-04.cleardb.com/heroku_b04f71f6e232c42?reconnect=true
```

確認できました。:relaxed:

### Dockerfileを開発環境用と本番用に用意

処理が本番とローカルで若干違うのでそれぞれごとに設定していきます。

projectのTOP階層に`start.sh`というファイルを一旦作成します。

ここに、本番環境特有の処理を書いておきます。

次に、`Dockerfile`を修正します。環境変数を設定したいので

before

```Dockerfile:Dockerfile
FROM ruby:2.7

# Yarnのレポジトリを有効化。レポジトリのGPGキーをcurlコマンドを使って取得する(debianはubuntuと互換性がある)
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -

# YarnのAPTパッケージレポジトリを自分のシステムに追加。teeコマンドを使って書き込み。
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

# レポジトリがシステムに加えられたらパッケージリストをアップデートしてからYarnをインストールする
RUN apt-get update -qq
RUN apt-get install -y nodejs yarn

# Dockerコンテナ上の作業ディレクトリ
WORKDIR /app

# ローカル開発環境の./src配下の内容をDockerコンテナ上の/appにコピー
COPY ./src /app

# gemファイルのインストール
RUN bundle config --local set path 'vendor/bundle' && bundle install
```

after

```Dockerfile:Dockerfile
FROM ruby:2.7

# 環境変数の設定
ENV RAILS_ENV=production

# Yarnのレポジトリを有効化。レポジトリのGPGキーをcurlコマンドを使って取得する(debianはubuntuと互換性がある)
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -

# YarnのAPTパッケージレポジトリを自分のシステムに追加。teeコマンドを使って書き込み。
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

# レポジトリがシステムに加えられたらパッケージリストをアップデートしてからYarnをインストールする
RUN apt-get update -qq
RUN apt-get install -y nodejs yarn

# Dockerコンテナ上の作業ディレクトリ
WORKDIR /app

# ローカル開発環境の./src配下の内容をDockerコンテナ上の/appにコピー
COPY ./src /app

# gemファイルのインストール
RUN bundle config --local set path 'vendor/bundle' && bundle install

# ローカル開発環境のstart.shの内容をDockerコンテナ上の/start.shにコピー
COPY start.sh /start.sh
# Docker側の下記のファイルに実行権限を渡すので権限を変更する
RUN chmod 744 /start.sh
# 実行
CMD ['sh', '/start.sh']
```

Dockerファイルはif文の条件を書きにくいので`sh`でやらせています。

ですが、本番環境用の処理をさせたいので、このファイルを作成しました。

本番環境の時だけ下記の処理を実行させる必要があるので記載しました。

```bash
bundle exec rails assets:precompile
```

最後はRailsでサーバを起動させています。

Dockerファイルでは、実務でも本番環境にだけ特定の処理をさせたい時は`.sh`ファイルにその処理をさせる方法はよくあるらしい。

もしくは、環境ごとDockerファイルを分ける方法もあるみたいです。

では、本番環境で`assets:precompile`が　を　させたいので、以下のコマンド（環境変数の追加）を実行します。

```bash
heroku config:add RAILS_SERVE_STATIC_FILES='true' -a rails-docker-ryosuketter

Setting RAILS_SERVE_STATIC_FILES and restarting ⬢ rails-docker-ryosuketter... done, v9
RAILS_SERVE_STATIC_FILES: true
```

追加されましたね。

```bash
heroku config -a rails-docker-ryosuketter
=== rails-docker-ryosuketter Config Vars
APP_DATABASE:             heroku_b04f71f6e232c42
APP_DATABASE_HOST:        us-cdbr-east-04.cleardb.com
APP_DATABASE_PASSWORD:    3f7958e7
APP_DATABASE_USERNAME:    b86d7f293af671
CLEARDB_DATABASE_URL:     mysql://b86d7f293af671:3f7958e7@us-cdbr-east-04.cleardb.com/heroku_b04f71f6e232c42?reconnect=true
RAILS_SERVE_STATIC_FILES: true
```

続いて、herokuをデプロイした時にPORT番号をサーバがバインドするのですが、それがデフォルトだと60sと指定されています。

それだと、タイムアウトしてしまうエラーが起こりやすいので、今のうちにその設定を120sに変更（伸ば）しておきましょう。

https://tools.heroku.support/limits/boot_timeout

![スクリーンショット 2021-09-26 23.25.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/10225c16-60a1-f74f-d03c-1811991f5746.png)

![スクリーンショット 2021-09-26 23.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/eb0103a4-d37c-ef42-8f8f-13165353556d.png)

できた。

続いて、ローカルのwebサーバを削除します。

なぜか？

ローカルでwebサーバが起動しているとherokuでwebサーバが起動しない可能性があるらしい。

```bash
docker-compose down

[+] Running 6/6
 ⠿ Container rails_docker_web_run_d27f4d8e6fab  Removed                                           3.8s
 ⠿ Container rails_docker_web_run_102cb7842969  Removed                                           0.2s
 ⠿ Container rails_docker_web_1                 Removed                                           1.1s
 ⠿ Container rails_docker_web_run_27c0fb3bd90f  Removed                                           0.2s
 ⠿ Container rails_docker_db_1                  Removed                                           2.4s
 ⠿ Network rails_docker_default                 Removed                                           0.4s
```

念の為、以下のファイルも削除しましょう。

```bash
rm src/tmp/pids/server.pid
```

これで、Dockerfileを開発環境用と本番用に用意が完了しました。

### Dockerイメージをビルド・リリース

まず、Dockerイメージをビルドして、コンテナレジストリにpushしていきます。

```bash
heroku container:push web -a rails-docker-ryosuketter

latest: digest: sha256:c455d738b066901456f59967b176ea84c0559cda0c575b231f62b5ea2302f385 size: 3888
Your image has been successfully pushed. You can now release it with the 'container:release' command.
```

コレで、Dockerイメージをビルドして、コンテナレジストリにプッシュするところまで完成しました。

続いて、コンテナレジストリにあげたイメージから、herokuの方にDockerコンテナをリリースしていきます。

```bash
heroku container:release web -a rails-docker-ryosuketter

Releasing images web to rails-docker-ryosuketter... done
```

これで、Dockerのコンテナをherokuにリリースできました。

続いて、DBのマイグレーションをしていきます。

```bash
heroku run bundle exec rake db:migrate RAILS_ENV=production -a rails-docker-ryosuketter

Running bundle exec rake db:migrate RAILS_ENV=production on ⬢ rails-docker-ryosuketter... up, run.5407 (Free)
```

では、herokuのアプリを開いていきます。

リリースしたherokuのアプリケーションを見てみます。

```bash
heroku open -a rails-docker-ryosuketter
```

最後にrouteに合わせたページを作成してそれを表示させたら完成です！

https://rails-docker-ryosuketter.herokuapp.com/

（今はアクセスできません）

お疲れ様でした！

:clap_tone1:

## さいごに

4連休を利用して、Dockerを理解できるようにがんばりました。

最終的に、4日で9記事書くことができました。

記事作成が目的ではなく、あくまでも開発環境で使いこなせるスキルにすること。丸暗記してたDockerコマンドを１つ１つ理解して使えるようになることが目的です。

実務でいきなりバリバリに使えるようになるのはムズいかもしれません。

ですが、かつての自分は概要の理解も無いし、実際に手も動かしていなかったです。

この4日を通じて一定の理解を得たので実務に以下していきます。

とりあへず完走した自分を褒めたい。

:relaxed:

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103