HerokuでFlask

大晦日にガキ使見ながらクソアプリを作ってHerokuにホストした
http://otoshidama.herokuapp.com/

こういうクソアプリは簡単に作れて、簡単にホストできないといけない。PythonのWAFはDjangoとかPyramidとか色々あるけど、個人的に最近はFlaskが好き。クソアプリ作るのにDjangoでゴニョゴニョ設定ファイルいじったりするの面倒だし、クソアプリにとっては余計な機能が多い。その点、Flaskはシンプルで良い。ホスティングサービスはAppEngineとかあるけど、Herokuのほうが何か格好いいし、使ってみてすごく簡単だった。

というわけで、これからもFlask + Herokuの組合せは使いそうなのでメモしておく。

Herokuのセットアップ

Herokuの登録はメールアドレスだけでいいので一瞬で終わる。
そのあとHeroku Toolbeltをインストールする。
https://toolbelt.heroku.com/
これを入れるとherokuコマンドとかが入って、これを使ってサーバ上のログを見たり、アドオン入れたり出来る。
そのあと

% heroku login

をして終わり。

ローカルのセットアップ

Heroku上にアプリケーションを認識させる

Herokuではgitを使ってデプロイするので、あらかじめgitのレポジトリを作っておく。
それからtoolbeltで入ったherokuコマンドで、アプリケーションを作成する。すでに作ってあるFlaskアプリのディレクトリに行って

% heroku create

これで適当な名前が割り当てられて、その名前がサブドメインになる。と同時に、gitのリモートレポジトリが追加される。ここで付けられた名前は後でコンパネで変えられる。指定したい場合は

% heroku create hoge

ここではhogeがアプリケーション名になる。この場合だとアプリケーションのURLは http://hoge.herokuapp.com になる。それからこのタイミングで、既にコンパネでアプリケーションの設定とか出来る。

Pythonモジュールの依存関係

その次に、Pythonモジュールの依存関係を書きだしておく。HerokuのDBはPostgresqlなので、必要なモジュールを入れておく。自分はSQLAlchemyを使っているので、Flask-SQLAlchemyとpsycopg2を入れている。

% pip install flask-sqlalchemy psycopg2

必要なモジュールをrequirements.txtに書き出しておく。

% pip freeze > requirements.txt

このrequirements.txtに書かれたモジュールはデプロイした時に勝手にインストールされる。容量制限があるので、あらかじめvirtualenvで環境を分けて必要なモジュールだけ書きだすようにした方がいい。

デプロイ用の設定

そして、アプリケーションの実行コマンドをProcfileに書いておく。クソアプリだから

web: python main.py

とかでいいと思う。

gunicornを使う場合は

web: gunicorn main:app -w 4

とか。

Flaskの簡易サーバを使うときは、このまま起動するとlocalhost:5000で立ち上げるけど、5000番勝手に使ってんじゃねえよって起こられるのでmain.pyを少し書き換える。

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(host="0.0.0.0", port=port)

gunicornを使うときは普通にapp.run()でいい。

DBの設定

HerokuはPostgresqlが無料で使えるらしいので、使わせていただく。
まず、Herokuのアドオンを追加する。昔はshared-dbっていうのが無料で使えるやつだったらしいけど、今はheroku-postgresql:devになっている。

% heroku addons:add heroku-postgresql:dev
% heroku config | grep HEROKU_POSTGRESQL

反映されるまでに少し時間が掛かることがあるらしいが、反映されたらconfigで

HEROKU_POSTGRESQL_PURPLE_URL: postgres://vsfgqiuiqcbp...

みたいなのが出る。そしたらそのDB(HEROKU_POSTGRESQL_PURPLE_URL)をアプリケーションで使うことをHerokuに知らせる。

% heroku pg:promote HEROKU_POSTGRESQL_RED_URL

これで環境変数DATABASE_URLがセットされる。この環境変数をFlaskアプリの中で指定する。

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"]

この時点でファイル構成は以下のようになっている。git周りは省略

% tree .          
.
├── Procfile
├── main.py
├── requirements.txt
└── templates
    └── index.html

最後にここまでの変更を全部コミットして、デプロイする。

% git push heroku master

アプリケーションの中でテーブルの初期化とかしていない場合は、サーバ上でPythonのインタープリタを起動して初期化すればいい。

% heroku run python
>> from main import db
>> db.create_all()

これでちゃんと動けば幸せ。

% heroku open

してちゃんと動いてることを確認する。

ちなみにログは

% heroku logs

で見られる。

簡単すぎる。今年はこんなクソアプリを量産して、WEB上をゴミアプリで埋め尽くしたい。