Herokuデプロイ方法【Heroku+Flask+MySQL】

DBにMySQLを使用したFlaskアプリをHerokuにデプロイした時に、詰まったので
備忘録として記録します。
同じことで詰まった方の少しでも参考になればと思います。

# 手順
1. デプロイ前にHerokuに必要なファイルを用意する
2. HerokuのDBをMySQLに変更
3. Herokuにデプロイ

# デプロイ前にHerokuに必要なファイルを用意する
Herokuにデプロイするために必要なファイルが3つあります。
これを作っていきます。
また3つのファイルはルートディレクトリに作成します。

- requirements.txt
- runtime.txt
- Procfile


## 必要なパッケージをrequirements.txtに定義
アプリに必要なパッケージをrequirements.txtに定義しておきます。
pipであれば以下のコマンドでインストールしているパッケージが出力されます。

```
$ pip freeze > requirements.txt
```
pipenvの場合は以下のようにすると出力されます。

```
$ pipenv lock -r
```

実行結果をrequirements.txtに記載しておきます。
自分の場合は以下のようになりました。

```python:requirements.txt
alembic==1.1.0
click==7.0
flask-migrate==2.5.2
flask-sqlalchemy==2.4.0
flask-wtf==0.14.2
flask==1.1.1
itsdangerous==1.1.0
jinja2==2.10.1
mako==1.1.0
markupsafe==1.1.1
numpy==1.17.1
psycopg2==2.8.3
pymysql==0.9.3
python-dateutil==2.8.0
python-editor==1.0.4
six==1.12.0
sqlalchemy==1.3.8
werkzeug==0.15.5
wtforms==2.2.1
```

## Procfileを作る
> Procfileとは
Herokuのプラットフォーム上にあるWebアプリがどのようなコマンドで実行されるのかを記述するファイルのこと。Webアプリを動かす指示書みたいなもの。

先にWebアプリとサーバーをつなぐための`gunicorn`というパッケージをインストールしておきます。

```
$ pip install gunicorn

# pipenvの場合
$ pipenv install gunicorn
```

インストールできたら以下のように実行するファイル名を設定しておきます。

```python:Procfile
web: gunicorn <実行するファイル名>:app --log-file=-
```
私の環境では「manage.py」が実行するファイルなので以下のようになりました。

```python:Procfile
web: gunicorn manage:app --log-file=-
```

また先ほどインストールした`gunicorn`を`requirements.txt`に追加しておきます。

```python:requirements.txt
# 追加
gunicorn==19.9.0
```

## runtime.txtでPythonのバージョンを定義
runtime.txtをルートディレクトリに作成し、Pythonのバージョンを記載します。
このファイルは、スペースなど余計なものが含まれているとエラーになるので注意します。

```python:runtime.txt
python-3.7.3
```

# HerokuのDBをMySQLに変更

## Herokuアプリ作成
Herokuにターミナルでログイン

```
$ heroku login
```
Heroku上でアプリ作成

```
$ heroku create アプリ名
```

## HerokuにClearDBを追加する
事前にHerokuでクレジットカードの登録が必要なので、登録しておきます。
以下の記事を参考にしてみてください。
https://wp.developapp.net/?p=5250

HerokuにClearDBのアドオンを追加します。
> ClearDBとは
Herokuでは、ClearDBというクラウドサービスのMySQLを利用することができます。ClearDBは、DBaaS で、バックアップやメンテナンスといった面倒な管理作業はプラットフォームが行ってくれます。"ignite" と呼ばれるデータ容量5MBの最小構成であれば無料で使えますので、こちらを利用します。

```
$ heroku addons:create cleardb:ignite
```

## HerokuでDB情報の環境変数を設定する
まずHeroku上での変数を確認します。

```
$ heroku config
```
以下のような書式で出力されます。

```
mysql://[username]:[password]@[hostname]/[db_name]?reconnect=true
```
上記のURLを元に`DATABASE_URL`をMySQL2に切り替えます。
コピーペーストしつつmysql2に書き換えてください。

```
$ heroku config:set DATABASE_URL='mysql2://[username]:[password]@[hostname]/[db_name]?reconnect=true'
```
私の場合はこれで書き換えられずかなり詰まりました。。。。。
色々試行錯誤し、以下の記事を参考にやったところやっとできました…！
https://qiita.com/kenzoukenzou104809/items/8f95967601e587e14812

次にHerokuの環境変数も設定しておきます。

```
$ heroku config:add DB_USERNAME="[username]"
$ heroku config:add DB_PASSWORD="[password]"
$ heroku config:add DB_HOSTNAME="[hostname]"
$ heroku config:add DB_NAME="[db_name]"
```

## FlaskアプリのSQLAlchemyの設定を変更

DBのURLを先ほど設定したClearDBのURLに変更します。
DBの情報は先ほどHerokuで設定した環境変数を使っています。

```python:config.py
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://{user}:{password}@{host}/{db}?charset=utf8'.format(**{
    'user': os.getenv('DB_USER', os.environ['DB_USERNAME']),
    'password': os.getenv('DB_PASSWORD', os.environ['DB_PASSWORD']),
    'host': os.getenv('DB_HOST', os.environ['DB_HOSTNAME']),
    'db': os.getenv('DB_NAME', os.environ['DB_NAME']),
})
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = False
```

## セキュリティ上の設定

ローカルの開発環境と本番の開発環境の設定を分けるために、ファイルを分けます。

```python:config.py
import os

# Flask
DEBUG = False

# local_config.pyファイルを読み込み
try:
    from .local_config import *
except ImportError:
    pass

if not DEBUG:
    # SECRET_KEY設定
    SECRET_KEY = os.environ['SECRET_KEY']

    # sqlalchemy設定
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://{user}:{password}@{host}/{db}?charset=utf8'.format(**{
        'user': os.getenv('DB_USER', os.environ['DB_USERNAME']),
        'password': os.getenv('DB_PASSWORD', os.environ['DB_PASSWORD']),
        'host': os.getenv('DB_HOST', os.environ['DB_HOSTNAME']),
        'db': os.getenv('DB_NAME', os.environ['DB_NAME']),
    })
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = False
```

```python:local_config.py
import os

DEBUG = True

SECRET_KEY = 'SECRET_KEY'

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://{user}:{password}@{host}/DB名?charset=utf8'.format(**{
    'user': os.getenv('DB_USER', 'ユーザー'),
    'password': os.getenv('DB_PASSWORD', 'パスワード'),
    'host': os.getenv('DB_HOST', 'localhost'),
})
```

## Herokuでマイグレーション
DBの設定を変更するために、Heroku上でマイグレーションを行います。
私の環境では以下のコマンドで実行しました。

```
heroku run FLASK_APP=manage.py flask db migrate
```

# Herokuにデプロイ
Herokuにデプロイする準備ができたので、FlaskアプリをHerokuにデプロイします。

```
$ git add .
$ git commit -m "Herokuデプロイのための設定"
$ git push heroku master
```
これで無事Herokuにデプロイすることができました！

# さいごに
DjangoのアプリをHerokuにデプロイした際は、DBの設定などあまり必要なかったのですが、今回Flaskでアプリを作ったことでHerokuのDBの設定などかなり詰まる部分があり大変でしたが、かなり勉強になりました。


# 参考
https://tanuhack.com/python/deploy-flask-heroku/
https://qiita.com/kenzoukenzou104809/items/8f95967601e587e14812
https://creepfablic.site/2019/06/15/heroku-procfile-matome/