はじめに
およそ1年前にDjangoを使って簡単なWebアプリを開発した。
データ収集からAI開発、Webアプリ公開まで全てPythonで済ませた話
入力されたURLからスクレイピングでデータ取得→学習済み機械学習モデルで推論→答えを返す
という非常にシンプルなものである。アプリはこちら↓
キー判別AI
久しぶりに使ってみたところ、スクレイピング先のサイトの仕様変更により、正しい結果を得られなくなってしまった。これはマズイと思い改修することにした。
久しぶりにコードを覗いてみたが、自分でもよくわからない…開発当時はとにかく動かすことを目標にしていたこともあり、コードも汚いし、デプロイ方法もすっかり分からなくなっている…
というわけで、今後も不定期的に改修することを考え、開発やデプロイをしやすくするために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
環境構築
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
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をインストールしています。こちらの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/
にアクセスすればアプリが走っていることが分かります。
Herokuにデプロイ
Herokuへの会員登録は済ませているものとします。
準備
- requirements.txt
必要なライブラリをrequirements.txtに書き込みます。デプロイのためにgunicorn
が必要なので、pipで忘れずにインストールしておきましょう。 - Procfile
プロジェクト直下に作成します。以下のように書きます。
左のappがプロジェクト直下のapp.pyのことで、右のappはapp.pyで定義したFlaskインスタンスの変数名?です。
ちょっと何言ってるか分かりづらいと思うので、こちらを読んでください。
https://stackoverflow.com/questions/19352923/gunicorn-causing-errors-in-heroku
web: gunicorn app:app --log-file -
アプリ作成
ターミナルからでもできますが、ブラウザからの方が分かりやすいので、ブラウザでやります。
- ブラウザからHerokuにログイン
https://id.heroku.com/login - New -> Create new app でアプリを作成
適当に名前をつけます。 - ビルドパックの追加
今回のアプリが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のコンテナに入ってデプロイします。
- herokuにログイン
リンクが出てくると思うので、それをクリックして認証する。
root@a59194fe1893:/home/KJA_APP# heroku login
- herokuのアプリ用リポジトリにpushする。
urlはhttps://git.heroku.com/[上の2.で作成したアプリ名].git
です。(ブラウザのSettingsでも確認できます)。
下のコマンドは、今のブランチの内容をherokuのリポジトリのmasterブランチにpushする、という意味です。
root@a59194fe1893:/home/KJA_APP# git push https://git.heroku.com/[上の2.で作成したアプリ名].git master
エラーがでなければこれにてデプロイ完了となります。
最後に
docker-compose便利ですね。