Dockerでflask+Herokuのための環境構築からデプロイまで

# はじめに
およそ1年前にDjangoを使って簡単なWebアプリを開発した。

[データ収集からAI開発、Webアプリ公開まで全てPythonで済ませた話](https://qiita.com/hanata/items/48e84fb051f4b7e04ac1)

`入力されたURLからスクレイピングでデータ取得→学習済み機械学習モデルで推論→答えを返す`
という非常にシンプルなものである。アプリはこちら↓
[キー判別AI](https://kja-app.herokuapp.com/)

久しぶりに使ってみたところ、スクレイピング先のサイトの仕様変更により、正しい結果を得られなくなってしまった。これはマズイと思い改修することにした。

久しぶりにコードを覗いてみたが、自分でもよくわからない…開発当時はとにかく動かすことを目標にしていたこともあり、コードも汚いし、デプロイ方法もすっかり分からなくなっている…

というわけで、今後も不定期的に改修することを考え、開発やデプロイをしやすくするために**Docker**での環境構築を実施した。クローンしてdocker-composeすれば開発できて、なおかつコンテナからherokuにデプロイできるようにするのを目標とする。

また、このアプリ自体がDBも使わず非常にシンプルなので、明らかにDjangoを使う必要もないので、この機会にflaskに書き換えちゃいます。

Githubにコードを公開しています。
https://github.com/hatena-hanata/KJA_app


# ディレクトリ構造
最終的なディレクトリ構造はこちらです。

```
KJA_APP
├── Dockerfile
├── Procfile
├── app.py
├── docker-compose.yml
├── requirements.txt
└── src
    ├── modules
    │   ├── module.py
    │   └── music_class.py
    ├── static
    │   └── model
    │       ├── le.pkl
    │       └── model.pkl
    └── templates
```

# 環境構築

```dockerfile:docker-compose.yml

version: '3'

services:
  web:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - .:/home/KJA_APP
    tty: true
    environment:
      TZ: Asia/Tokyo
    command: flask run --host 0.0.0.0 --port 8080

```

```dockerfile:Dockerfile
FROM python:3.8.0
USER root

# install google chrome
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
RUN apt-get -y update && apt-get install -y google-chrome-stable && apt-get install -yqq unzip

# install chromedriver
RUN wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip
RUN unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/

# install heroku cli
RUN curl https://cli-assets.heroku.com/install.sh | sh

# set display port to avoid crash
ENV DISPLAY=:99

# upgrade pip
RUN apt-get update && apt-get install -y \
	&& pip install --upgrade pip

# change dir
WORKDIR /home/KJA_APP

# install module
COPY requirements.txt /home
RUN pip install -r /home/requirements.txt

# flask setting
ENV FLASK_APP '/home/KJA_APP/app.py'
ENV FLASK_DEBUG 1
```

今回、seleniumでchromeを動かしてスクレイピングするため、最初にchromeとchrome driverをインストールしています。[こちら](https://github.com/joyzoursky/docker-python-chromedriver)のdockerfileを参考にしました。
また、herokuへのデプロイのために、heroku cliもインストールしています。

最後の2行flask settingでは、flaskに関する設定を行っています。
`FLASK_APP`では、flaskのメイン関数のあるpyファイルを指定することで、`flask run`コマンドでそのファイルが実行されるようになります。
`FLASK_DEBUG`を1にすることでデバッグモードになり、ファイルの更新がリアルタイムで反映されるようになります。

これにて、git clone→docker-composeですぐに開発ができるようになりました。docker-composeの際に`flask run`コマンドを実行しているので、`http://localhost:8080/` にアクセスすればアプリが走っていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405491/a0a67582-e0e3-d702-3712-48e0c164aa1f.png)


# Herokuにデプロイ
Herokuへの会員登録は済ませているものとします。
## 準備
1. requirements.txt  
必要なライブラリをrequirements.txtに書き込みます。デプロイのために`gunicorn`が必要なので、pipで忘れずにインストールしておきましょう。
2. Procfile  
プロジェクト直下に作成します。以下のように書きます。  
左のappがプロジェクト直下のapp.pyのことで、右のappはapp.pyで定義したFlaskインスタンスの変数名？です。
ちょっと何言ってるか分かりづらいと思うので、こちらを読んでください。  
https://stackoverflow.com/questions/19352923/gunicorn-causing-errors-in-heroku

```:Procfile
web: gunicorn app:app --log-file -
```

## アプリ作成
ターミナルからでもできますが、ブラウザからの方が分かりやすいので、ブラウザでやります。

1. ブラウザからHerokuにログイン  
https://id.heroku.com/login
2. New -> Create new app でアプリを作成  
適当に名前をつけます。
3. ビルドパックの追加  
今回のアプリがpythonであることを明示するために、作成したアプリのページで Settings -> Buildpacks から `heroku/python` を追加します。
(デプロイ時に自動でpythonを追加してくれる場合もあるそうですが、自分のディレクトリ構造が悪かったせいか、pythonプロジェクトと認識されず困ったので、予め手動で追加しておくことをオススメします。）  
また、今回はseleniumとchromeを利用したスクレイピングをするため、chromeとchrome driverが必要になります。これもビルドパックの追加で対応できます。  
https://qiita.com/nsuhara/items/76ae132734b7e2b352dd#chrome%E3%81%A8driver%E3%81%AE%E8%A8%AD%E5%AE%9A

## デプロイ
ここからはDockerのコンテナに入ってデプロイします。
1. herokuにログイン
リンクが出てくると思うので、それをクリックして認証する。

```bash
root@a59194fe1893:/home/KJA_APP# heroku login
```
2. herokuのアプリ用リポジトリにpushする。
urlは `https://git.heroku.com/[上の2.で作成したアプリ名].git` です。（ブラウザのSettingsでも確認できます）。  
下のコマンドは、今のブランチの内容をherokuのリポジトリのmasterブランチにpushする、という意味です。

```bash
root@a59194fe1893:/home/KJA_APP# git push https://git.heroku.com/[上の2.で作成したアプリ名].git master
```

エラーがでなければこれにてデプロイ完了となります。

# 最後に
docker-compose便利ですね。