ローカルで作成したdocker イメージをherokuにデプロイする方法（備忘録）

##はじめに
Dockerで開発環境を作成し、ローカルで開発したアプリケーションをherokuを使ってデプ
ロイする際に、当初うまくいかなかったので、その手順について、備忘録としてここに
残します。
####herokuとは
>Heroku はアプリの構築、提供、監視、スケールに役立つクラウドプラットフォーム

引用：[Heroku とは | Heroku](
https://jp.heroku.com/what#:~:text=Heroku%20%E3%81%AF%E3%83%87%E3%83%BC%
E3%82%BF%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E3%8
3%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC
%E3%83%A0%E3%81%A7%E3%80%81%E5%AE%89%E5%85%A8%E6%80%A7%E3%
81%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%A9%E3%83%93%E3%83%A
A%E3%83%86%E3%82%A3%E3%81%AB%E5%84%AA%E3%82%8C%E3%81%9F,Daa
S%EF%BC%88%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A8%E3
%81%97%E3%81%A6%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%83%
99%E3%83%BC%E3%82%B9%EF%BC%89%E3%81%A8%E3%80%81%E3%83%87%E
3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83
%95%E3%82%A9%E3%83%AD%E3%83%AF%E3%83%BC%E3%80%81%E3%83%95%
E3%82%A9%E3%83%BC%E3%82%AF%E3%80%81Dataclips%E3%80%81%E8%87%A
A%E5%8B%95%E3%83%98%E3%83%AB%E3%82%B9%E3%83%81%E3%82%A7%E3
%83%83%E3%82%AF%E3%81%AA%E3%81%A9%E3%81%AE%E5%A4%9A%E6%95
%B0%E3%81%AE%E9%96%8B%E7%99%BA%E8%80%85%E5%90%91%E3%81%91%
E3%83%84%E3%83%BC%E3%83%AB%E3%81%A7%E6%A7%8B%E6%88%90%E3%8
1%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82
%20%E9%87%8D%E8%A6%81%E3%81%AA%E3%82%A2%E3%83%97%E3%83%AA%
E3%81%A7%E3%81%AF%E3%80%81%E4%BE%8B%E5%A4%96%E3%81%AA%E3%8
1%8F%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8C%E4%B8%AD%E6%A0%B
8%E3%81%AB%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)
####Cf. クラウドプラットフォームとは
>クラウド型プラットフォームとは、アプリケーション実行やデータ保存ができる基盤を、WEB上で展開しているものです。

引用：[IT業界初心者必見！クラウド型プラットフォームとは？ | ITコラムdeパイプドビッツ｜パイプドビッツ公式HP(pi-pe.co.jp)]( https://www.pi-pe.co.jp/solution/article/xrad/284/)
####1.デプロイ事前準備
#####前提条件
- macOSで開発
- Heroku の無料アカウントを取得済み
- Ruby2.7を使用している。
- Bundlerインストール済み
- Git インストール済み（HerokuCLIを利用するために必要）

#####1-1 Heroku Command Line Interface(HerokuCLI)のインストール
~~~terminal
$brew install heroku/brew/heroku
~~~

これで、ターミナルからherokuをコマンドラインで操作できるようになりました。
#####1-2ターミナルからHerokuにログイン
~~~terminal
$heroku login
heroku: Press any key to open up the browser to login or q to exit
› Warning: If browser does not open, visit
› https://cli-auth.heroku.com/auth/browser/***
heroku: Waiting for login...
Logging in... done
Logged in as me@example.com
~~~
何かキーを押すようにと指示されるので、そのままキーを押します。ブラウザが自動で開
くので、”log　in”ボタンをクリックしてください。
ターミナル上に”login succeeded”と表示されれば、ログイン成功です。
これで、ターミナル上で、gitとherokuコマンドを正しく扱うことができるようになります
。
参考：[Getting Started on Heroku with Ruby | Heroku DevCenter](https://devcenter.heroku.com/articles/getting-started-with-ruby#deploy-the-app)
####2.Heroku上にアプリケーションを作成。
Herokuにdockerイメージをデプロイする方法は2つあります。

- コンテナレジストリ を使用して、事前にビルドされた Docker イメージを Heroku にデ
プロイする方法。
- heroku.yml を使用して、 Docker イメージをビルドして、Heroku にデプロイする方法
。
今回は、前者の方法を使用したので、前者の方法について記載します。

#####2-1 Heroku コンテナレジストリにログイン
~~~terminal
$heroku container:login
~~~
これで、ローカルで作成したdockerイメージをheroku　コンテナレジストリにアップする
ことができるようになりました。
#####2-2 Herokuでアプリケーションを作成
~~~terminal
$heroku create アプリケーション名
Creating アプリケーション名... done, stack is heroku-20
https://アプリケーション名.herokuapp.com/ | https://git.heroku.com/アプリケーション名.git
~~~

ここで設定する、アプリケーション名については、heroku上でユニークな名前でなければいけません。
アプリケーション名に問題が無ければ、アプリケーションが作成されます。
この時、以下の２つのURLが生成されます。

- 作成されたアプリケーションへのURL(`https://アプリケーション名.herokuapp.com`)
- githubのリモートレポジトリへのURL(`https://git.heroku.com/アプリケーション名.git`)

####3.データベースの設定
#####3-1 本番環境用のデータベース接続先の設定

実は、database.ymlファイルのproduction:の部分には、次のような説明書きが記載されています。

~~~yaml
# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password or a full connection URL as an environment
# variable when you boot the app. For example:
#
#   DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
#
# If the connection URL is provided in the special DATABASE_URL environment
# variable, Rails will automatically merge its configuration values on top of
# the values provided in this file. Alternatively, you can specify a connection
# URL environment variable explicitly:
#
#   production:
#     url: <%= ENV['MY_APP_DATABASE_URL'] %>
#
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified.
#
~~~
この部分をちゃんと確認しないまま進めてしまい、この後、heroku上でrails db:migrateができないという問題に陥りました。。。。私の場合は、DATABASE_URLという環境変数を設定していなかったがために、以下のエラーが発生しました。

~~~terminal
Mysql2::Error::ConnectionError: Unknown MySQL server host
~~~

この説明書きによると、railsにおける、本番環境のデータベースの接続先の設定方法は、以下の２つがあるようです。セキュリティーの観点からデータベースの接続先情報が外部から確認できない方法が取られています。

- config/credentials.ymlを使う方法
- DATABASE_URLという特別な環境変数に完全な接続先のURLを設定する方法

今回は後者の方法で設定しました。
ローカルのsrc/config/database.ymlファイルを本番環境用に次のように設定します。

~~~yaml
production:
  <<: *default
  database: <%= ENV['APP_DATABASE'] %>
  username: <%= ENV['APP_DATABASE_USERNAME'] %>
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>
  host: <%= ENV['APP_DATABASE_HOST'] %>
~~~
#####3-2 herokuに環境変数を登録

ここからは、[公式のドキュメント](https://devcenter.heroku.com/articles/cleardb#provisioning-the-shared-mysql-add-on)を参考に進めていきます。

#####3-2-1 アプリケーションにデータべースをアドオンで追加

~~~terminal
$heroku addons:create cleardb:ignite -a アプリケーション名
-----> Adding cleardb to sharp-mountain-4005... done, v18 (free)
~~~
データベースには、ClearDB MySQLを使用します。
ClearDB MySQLは、クラウド上で提供されている MySQL データベースです。今回は、学習用なので、無料プランのigniteを使用しています。
#####3-2-2 データべース接続先URLの確認
ターミナルでデータベースの接続先のURLを確認します。

~~~terminal
$heroku config | grep CLEARDB_DATABASE_URL
CLEARDB_DATABASE_URL => mysql://adffdadf2341:adf4234@us-cdbr-east.cleardb.com/heroku_db?reconnect=true
~~~
データベースへの接続先のURLは、CLEARDB_DATABASE_URLという環境変数に格納されています。
URLについては、次のような構成になっています。

~~~terminal
mysql://[ユーザー名]:[パスワード]@[MySQLのホスト名]/[サービスのインスタンス名]
~~~
ここで１点修正が必要です。現在、mysql2 gemを使用しているため。公式ドキュメントに記載のある通り、mysql:// をmysql2://と変更します。

>If you’re using Ruby on Rails and the mysql2 gem, you will need to change the mysql:// scheme in the CLEARDB_DATABASE_URL to mysql2://

引用：[ClearDB MySQL](https://devcenter.heroku.com/articles/cleardb#provisioning-the-shared-mysql-add-on)

既存の環境変数の上書きは、次のコマンドで行います。

~~~terminal
$heroku config:set 環境変数=値
~~~

~~~terminal
$heroku config:set CLEARDB_DATABASE_URL=mysql2://adffdadf2341:adf4234@us-cdbr-east.cleardb.com/heroku_db?reconnect=true
~~~

|変更前|変更後|
|---|---|
|mysql://|mysql2://|


#####3-2-3 herokuに環境変数の登録
それでは、ローカルのdatabase.ymlに設定した環境変数の値をherokuで登録していきます。
herokuに環境変数を登録するコマンドは次の通りです。

~~~terminal
heroku config:add 環境変数名='値' -a アプリケーション名
~~~
下記のコマンドを一つずつ実行していきます。

~~~terminal
heroku config:add APP_DATABASE='heroku_db' -a アプリケーション名

heroku config:add APP_DATABASE_USERNAME='adffdadf2341' -a アプリケーション名

heroku config:add APP_DATABASE_PASSWORD='adf4234' -a アプリケーション名

heroku config:add APP_DATABASE_HOST='us-cdbr-east.cleardb.com' -a アプリケーション名
~~~

次に、環境変数DATABASE_URLにCLEARDB_DATABASE_URLの値を代入します。ここが一番大事です。この設定をしていないとアプリケーションがデータベースと接続できずに、エラーが発生してしまいます。

~~~terminal
$heroku config:add DATABASE_URL='mysql2://adffdadf2341:adf4234@us-cdbr-east.cleardb.com/heroku_db?reconnect=true'
Adding config vars:
DATABASE_URL => mysql2://adffd...b?reconnect=true
Restarting app... done, v61.
~~~

最後に環境変数RAILS_SERVE_STATIC_FILESにtrueを設定します。

~~~terminal
$heroku config:add RAILS_SERVE_STATIC_FILES='true' -a アプリケーション名
~~~
この環境変数を'true'で設定しておくことで、本番環境でassets:precompileが実行されるようになります。

#####cf. RAILS_SERVE_STATIC_FILESについて

~~~ruby:config/environments/production.rb
  # Disable serving static files from the `/public` folder by default since
  # Apache or NGINX already handles this.
  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
~~~

>  Disable serving static files from the `/public` folder by default since
   Apache or NGINX already handles this.

`/public` フォルダー配下の静的ファイルは、Apache or NGINXといったWEBサーバーに配信する責務があるため、rails(アプリケーションサーバー)では、デフォルトでは、配信できないようになっているようです。

今回は、railsでプリコンパイルした静的ファイルを扱いたいので、RAILS_SERVE_STATIC_FILESに値を設定しています。ちなみに、config.public_file_server.enabledがtrueになればいいので、RAILS_SERVE_STATIC_FILESの値は、なんでもいいです。

これで、必要な全ての環境変数をherokuに登録することができました！！

登録した環境変数は、下記コマンドで確認できます。

~~~
$heroku config -a アプリケーション名
~~~

####4.dockerイメージのビルドとイメージのプッシュ

~~~terminal
$heroku container:push web -a アプリケーション名
~~~
docker イメージをビルドして、コンテナレジストリにプッシュします。
コマンドを実行するディレクトリにdockerfileが存在することを確認してください。

#####cf.ローカル環境でdocker composeでWEBサーバーが起動している場合は、事前に終了してください。またpidファイルの削除も念の為に行ってください。

~~~terminal
$docker compose down
~~~

~~~terminal
$rm src/tmp/pids/server.pid
~~~
これをしていないと、herokuのWEBサーバーと設定がコンフリクトする可能性があるようです。
####5.dockerイメージのリリース

~~~terminal
$heroku container:release web -a アプリケーション名
~~~
コンテナレジストリのイメージをアプリケーションにリリースします。

####6.db:migrateを実行する。

~~~terminal
$heroku run bundle exec rake db:migrate RAILS_ENV=production -a アプリケーション名
~~~
マイグレーションファイルの内容からテーブルを作成、更新します。

####7.Change Boot Timeout
ポート番号へのバインドはデフォルトで６０秒で行われますが、herokuの無料プランのマシンパワーでは、６０秒を超過してタイムアウトとなり、エラー発生の原因となることから、１２０秒にタイムアウト時間を延長しておきます。
[https://tools.heroku.support/limits/boot_timeout](https://tools.heroku.support/limits/boot_timeout)

####8.アプリケーションをブラウザで開く。

~~~terminal
$heroku open -a アプリケーション名
~~~

以上で完了です！

##参考ページ

引用：[Heroku とは | Heroku](
https://jp.heroku.com/what#:~:text=Heroku%20%E3%81%AF%E3%83%87%E3%83%BC%
E3%82%BF%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E3%8
3%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC
%E3%83%A0%E3%81%A7%E3%80%81%E5%AE%89%E5%85%A8%E6%80%A7%E3%
81%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%A9%E3%83%93%E3%83%A
A%E3%83%86%E3%82%A3%E3%81%AB%E5%84%AA%E3%82%8C%E3%81%9F,Daa
S%EF%BC%88%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A8%E3
%81%97%E3%81%A6%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%83%
99%E3%83%BC%E3%82%B9%EF%BC%89%E3%81%A8%E3%80%81%E3%83%87%E
3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83
%95%E3%82%A9%E3%83%AD%E3%83%AF%E3%83%BC%E3%80%81%E3%83%95%
E3%82%A9%E3%83%BC%E3%82%AF%E3%80%81Dataclips%E3%80%81%E8%87%A
A%E5%8B%95%E3%83%98%E3%83%AB%E3%82%B9%E3%83%81%E3%82%A7%E3
%83%83%E3%82%AF%E3%81%AA%E3%81%A9%E3%81%AE%E5%A4%9A%E6%95
%B0%E3%81%AE%E9%96%8B%E7%99%BA%E8%80%85%E5%90%91%E3%81%91%
E3%83%84%E3%83%BC%E3%83%AB%E3%81%A7%E6%A7%8B%E6%88%90%E3%8
1%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82
%20%E9%87%8D%E8%A6%81%E3%81%AA%E3%82%A2%E3%83%97%E3%83%AA%
E3%81%A7%E3%81%AF%E3%80%81%E4%BE%8B%E5%A4%96%E3%81%AA%E3%8
1%8F%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8C%E4%B8%AD%E6%A0%B
8%E3%81%AB%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)
引用：[IT業界初心者必見！クラウド型プラットフォームとは？ | ITコラムdeパイプドビッツ｜パイプドビッツ公式HP(pi-pe.co.jp)]( https://www.pi-pe.co.jp/solution/article/xrad/284/)
参考：[Getting Started on Heroku with Ruby | Heroku DevCenter](https://devcenter.heroku.com/articles/getting-started-with-ruby#deploy-the-app)
参考：[Container Registry &amp; Runtime (Docker Deploys) | Heroku Dev Center](
https://devcenter.heroku.com/articles/container-registry-and-runtime)
参考：[ClearDB MySQL | Heroku Dev Center](
https://devcenter.heroku.com/articles/cleardb)