Heroku上の既存のアプリケーションにDockerを使用してデプロイする

# はじめに
Heroku上の既存のアプリケーションにDockerを使用してデプロイを行った際の備忘録になります。

# リポジトリ
https://github.com/b-coffin/heroku-docker-deploy-tutorial

# 事前準備
今回はnginxの公式イメージを使用して簡単なDockerイメージを作成します。

```dockerfile
FROM nginx:latest

WORKDIR /usr/share/nginx/html

COPY src /usr/share/nginx/html
COPY default.conf.template /etc/nginx/conf.d/default.conf.template

# Herokuではポート番号が動的に割り当てられるため、ポート番号をListenするために起動時に $PORT という環境変数を読み込む必要がある。
CMD /bin/sh -c "envsubst '\$PORT' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf" && nginx -g 'daemon off;'
```

注意点として、コメントにもありますが、**Herokuではポート番号が動的に割り当てられるため、nginxの設定ファイル内でListenするポート番号を指定する箇所に割り当てられたポート番号を記述する必要があります。**

今回は下記の設定ファイルを用意して、`$PORT` に割り当てられたポート番号読み込み、コンテナ内の `/etc/nginx/conf.d/default.conf` にコピーしています。

```conf
server {
    listen       $PORT;
    server_name  localhost;

...以下略
```

ファイルの詳細は上述のリポジトリを参照してください。

# 手順
大まかに下記のような流れで行います。

1. Heroku CLI をインストール
2. Herokuにログイン
3. コンテナイメージをデプロイ
4. 表示を確認

## 1. Heroku CLI をインストール
Heroku CLI を入れていなかったので、下記コマンドでインストールします。

```console
​$ ​brew tap heroku/brew && brew install heroku
```

参考: [Heroku CLI のインストール - Heroku](https://devcenter.heroku.com/ja/articles/heroku-cli#install-the-heroku-cli)

## 2. Herokuにログイン

```console
$ heroku login
```

参考: [Heroku CLI の開始](https://devcenter.heroku.com/ja/articles/heroku-cli#get-started-with-the-heroku-cli)

## 3. コンテナイメージをデプロイ
Container Registr にログインします。

```console
$ heroku container:login
```

既存のHerokuアプリケーションを対象のディレクトリと紐付けます。

```console
$ cd path/to/directory
$ heroku git:remote -a <Herokuアプリケーション名>
```

上記により、リモートリポジトリに `heroku` という名前のリポジトリが追加されます。

```console
$ git remote -v
heroku  https://git.heroku.com/<Herokuアプリケーション名>.git (fetch)
heroku  https://git.heroku.com/<Herokuアプリケーション名>.git (push)
...
```

イメージをビルドして Container Registry にプッシュするには、ディレクトリにDockerfileが存在していることを確認し、下記を実行します。
自分は M1 Mac を使用しているので、[こちらの記事](https://zenn.dev/daku10/articles/m1-heroku-container-trouble-exec-format-error)を参考にx86向けの Docker image　をビルドしてpushしています。

```console
$ docker buildx build . --platform linux/amd64 -t nginx_sample:latest
$ docker tag nginx_sample registry.heroku.com/<Herokuアプリケーション名>/<process-type>
$ docker push registry.heroku.com/<Herokuアプリケーション名>/<process-type>
```

イメージをpushしたら、そのイメージをアプリにリリースします。

```console
$ heroku container:release <process-type>
```

参考: [Container Registry および Runtime (Docker デプロイ) - Heroku](https://devcenter.heroku.com/ja/articles/container-registry-and-runtime)

## 4. 表示を確認
下記コマンドでHerokuのアプリケーションをブラウザで開きます。

```console
$ heroku open
```

# 参考
- [Heroku CLI - Heroku](https://devcenter.heroku.com/ja/articles/heroku-cli)
- [Container Registry および Runtime (Docker デプロイ) - Heroku](https://devcenter.heroku.com/ja/articles/container-registry-and-runtime)
- [Heroku CLI コマンド - Heroku](https://devcenter.heroku.com/ja/articles/heroku-cli-commands)
- [環境変数からのポートの取得 - Heroku](https://devcenter.heroku.com/ja/articles/container-registry-and-runtime#get-the-port-from-the-environment-variable)
- [Herokuで既存のアプリを公開する - Qiita](https://qiita.com/kaitaku/items/41f69b23fdf3a1148df6)
- [M1 MacでHeroku containerにデプロイしたら `Exec format error` と出て困った話](https://zenn.dev/daku10/articles/m1-heroku-container-trouble-exec-format-error)
- [極小のWebサーバーをHerokuにデプロイした - みーのぺーじ](https://pc.atsuhiro-me.net/entry/2021/02/26/214209)