Herokuにdockerコンテナアプリをデプロイする

## 対象読者
- ローカル環境もしくは別のサーバー上にすでにコンテナアプリを開発済みの方
- コンテナ上で開発したアプリをHerokuにデプロイしようと考えている方

## 筆者の環境
- Rails(API)
- React
- MySQL
- docker

rails，reactはそれぞれ別のコンテナとして開発を行った．

## Herokuに登録する
Herokuに会員登録をおこなう．(長くなってしまうのでここでは省略)
後で無料のアドオンを追加する際に必要となるのでクレジットカードの登録も合わせて行う．

## HerokuCLIをインストールする
コマンドでHerokuの操作を行うため以下の手順でHerokuCLIのインストールを行いましょう
- 以下のサイトにアクセスしてHerokuCLIのダウンロードを行う
https://devcenter.heroku.com/ja/articles/heroku-cli#install-the-heroku-cli
- コンテナアプリの置いてあるディレクトリに移る
例：cd Documents/docker/rails-react/backend
- コマンドラインからHerokuにログインする
この時のメールアドレスとパスワードはHerokuに登録したものを使う
```
> heroku login --interactive
```

## Herokuにrailsコンテナをデプロイする
- railsコンテナのディレクトリに移動して以下のコマンドを実行し，herokuアプリケーションを作成する
```
> heroku create [アプリ名]
```
- データベースを追加する
```
> heroku addons:create jawsdb:kitefin -a [アプリ名]
```
- config/database.ymlに本番環境用の環境変数を追加
```
production:
  <<: *default
  database: <%= ENV['APP_DATABASE'] %>
  username: <%= ENV['APP_DATABASE_USERNAME'] %>
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>
  host: <%= ENV['APP_DATABASE_HOST']%>
```
- データベースの登録情報を確認する
```
> heroku config -a [アプリ名]

JAWSDB_URL: mysql://[ユーザ名]:[パスワード]@[ホスト名]:3306/[データベース名]
```

- 以下のコマンドを順に実行しHerokuにDBの環境変数を設定する
```
> heroku config:add APP_DATABASE='[データベース名]' -a [アプリ名]
> heroku config:add APP_DATABASE_USERNAME='[ユーザ名]' -a [アプリ名]
> heroku config:add APP_DATABASE_PASSWORD='[パスワード]' -a [アプリ名]
> heroku config:add APP_DATABASE_HOST='[ホスト名]' -a [アプリ名]
```
- 環境変数が正しく設定されたか確認する
```
> heroku config -a [アプリ名]

APP_DATABASE:             [データベース名]
APP_DATABASE_HOST:        [ホスト名]
APP_DATABASE_PASSWORD:    [パスワード]
APP_DATABASE_USERNAME:    [ユーザ名]
JAWSDB_URL:               mysql://[ユーザ名]:[パスワード]@[ホスト名]:3306/[データベース名]
```
- Dockerfileを本番環境用に編集する
```
FROM ruby:3.0 

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs default-mysql-client

ENV RAILS_ENV=production  #ここだけ追加

ENV APP_PATH /myapp
RUN mkdir $APP_PATH
WORKDIR $APP_PATH

COPY Gemfile $APP_PATH/Gemfile
COPY Gemfile.lock $APP_PATH/Gemfile.lock

RUN bundle install

COPY . $APP_PATH

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

ENV PORT 3000
EXPOSE $PORT

CMD ["rails", "server", "-b", "0.0.0.0"]
RUN ["apt-get", "install", "-y", "vim"]
```
- herokuがポートをバインドできない場合を想定してtimeoutまでの時間を伸ばす
    - 以下のサイトにアクセス
    https://tools.heroku.support/limits/boot_timeout
    - アプリケーションを選択し，120秒に伸ばす

- ローカルでWEBサーバが起動している場合は停止させる
```
> docker-compose down
```
- railsコンテナのディレクトリ直下に「heroku.yml」ファイルを作成
- heroku.ymlファイルに以下を記述
```
build:
  docker:
    web: Dockerfile
run:
  web: bundle exec puma -C config/puma.rb
```
- herokuアプリのスタックをcontainerに変更する
```
> heroku stack:set container
```

- railsコンテナをpushする
    - herokuにログインする
    ``` 
    > heroku login --interactive
    ```
    - pushするコンテナのディレクトリに移動する
    - .gitignoreファイルを作成し，pushしないファイルを指定する
    - 以下のコマンドを順に実行し，pushとコンテナのビルドを行う
    ```
    > git init #最初だけ
    > heroku git:remote -a [アプリ名] #最初だけ
    > git add .
    > git commit -m "make it better"
    > git push heroku master
    ```
- herokuアプリを起動する
```
> heroku open -a [アプリ名]
```
- herokuアプリのログを確認する
```
> heroku logs --tail -a [アプリ名]
```
## Herokuにreactコンテナをデプロイする
- reactコンテナのディレクトリに移動して以下のコマンドを実行し，herokuアプリケーションを作成する
```
> heroku create [アプリ名]
```
- package.jsonに以下を追加
```
"license": "UNLICENSED",
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "eject": "react-scripts eject",
    "test": "react-scripts test"
},
```
- frontendディレクトリ直下にheroku.ymlファイルを作成し以下を記述
```
build:
    docker:
        web: Dockerfile
    config:
        NODE_ENV: production
run:
    web: sh -c "npm start"
```
-  Dockerfileを以下のように変更
```
FROM node:16.7-alpine3.11

WORKDIR /usr/src/app

COPY ["package.json","package-lock.json", "./"]


RUN npm install -g npm@8.10.0
RUN npm install -g react-scripts

COPY . .
```
- herokuアプリのスタックをcontainerに変更する
```
> heroku stack:set container
```
- herokuがポートをバインドできない場合を想定してtimeoutまでの時間を伸ばす
    - 以下のサイトにアクセス
    https://tools.heroku.support/limits/boot_timeout
    - アプリケーションを選択し，120秒に伸ばす

- ローカルでWEBサーバが起動している場合は停止させる
```
> docker-compose down
```
- reactコンテナをpushする
    - herokuにログインする
    ``` 
    > heroku login --interactive
    ```
    - pushするコンテナのディレクトリに移動する
    - .gitignoreファイルを作成し，pushしないファイルを指定する
    - 以下のコマンドを順に実行し，pushとコンテナのビルドを行う
    ```
    > git init #最初だけ
    > heroku git:remote -a [アプリ名] #最初だけ
    > git add .
    > git commit -m "make it better"
    > git push heroku master
    ```
- herokuアプリを起動する
```
> heroku open -a [アプリ名]
```
- herokuアプリのログを確認する
```
> heroku logs --tail -a [アプリ名]
```

## ローカルのデータを本番環境のデータベースに移す
- ローカル環境のdbのデータベースからdumpファイルを作成する
windowsの場合はpoweshellではなくコマンドラインでやらないと，リストアの際に文字コードでエラーが起こるので注意
```
> docker-compose exec -it db mysqldump -u [ユーザ名] -h [ホスト名] -p[パスワード] DB_NAME  TABLE_NAME > dump.sql
```
- dumpファイルを使って本番環境のdbにデータをコピーする
```
> mysql -u [user] -p[password] -h [host] --default-character-set=utf8mb4 [db_name] < dump.sql
```

# 引用
https://devcenter.heroku.com/ja/articles/build-docker-images-heroku-yml
https://devcenter.heroku.com/ja/articles/git
https://www.youtube.com/watch?v=lZD1MIHwMBY&t=8559s