Flaskで作ったアプリを、いざ本番環境にデプロイしようと思ったのだけど。なかなか一筋縄でいかず、結局丸一日向き合うことになった。Railsでやってた時は、heroku create
からのgit push heroku master
で瞬間に立ち上がっていたのに。
というわけで、FlaskをHerokuに立ち上げるまでを備忘録的に残していく。
開発環境
今回、デプロイにあたって使用した技術はこちら。
- Python 3.7.5
- Flask 1.1.1
- SQL Alchemy
- Flask Migrate
Flaskチュートリアルだと、db.create_all()
コマンドでDBを作成している。しかし、いわゆるマイグレーションファイルに慣れている人からすると、やはりテーブルの状態管理をしておきたいもの。そういう場合には、Flask Migrate
を使う。
アプリの初期構築
まずは、アプリの初期構築をやっていく。
Flaskはかなりカスタマイズ度が高いため、開発者によってディレクトリ構成が異なる。まだ、ベストプラクティスは模索中なのだが、最終的にはこんな感じになった。
app/
├── manage.py
├── main
│ ├── __init__.py
│ ├── views.py
│ ├── config.py
│ ├── models.py
│ ├── app.db
│ ├── static/
│ ├── templates/
│ └── instance
│ └──application.cfg
├── Procfile
├── requirements.txt
├── migrations/
└── venv/
プロジェクトの作成
$ cd APP
$ mkdir -p main/{static,templates,instance}
$ cd main
$ touch manage.py requirements.txt Procfile
$ touch main/{__init__,views,models,config}.py
お好みでスタイルシートや、ビュー部分を足す。今回は、HerokuでDBがちゃんと動いて、「Hello world!」を出すまでをやるので、バックエンドのみ。
manage.py
flaskを起動して実行するためのファイル。
from main import app
app.run()
main/init.py
flaskアプリを生成。
from flask import Flask
app = Flask(__name__)
import main.views
main/views.py
Hello world!を表示するビュー部分。
from flask import render_template
from main import app, db
@app.route('/')
def home():
return render_template('home/index.html')
設定ファイルの作成
このあたりはベストプラクティスの記事がたくさん上がっているので、そちらを参考にしてみると分かりやすいかと。ここでは、一応動くと、秘密なものは隠せるレベルのものを紹介する。
main/config.py
import os
class BaseConfig(object):
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(BaseConfig):
DEBUG = True
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db'
class ProductionConfig(BaseConfig):
DEBUG = True
TESTING = True
SQLALCHEMY_DATABASE_URI=os.environ.get('DATABASE_URL')
config = {
"default": "main.config.BaseConfig",
"development": "main.config.DevelopmentConfig",
"production": "main.config.ProductionConfig",
}
def configure_app(app):
config_name= os.getenv('FLASK_ENV')
app.config.from_object(config[config_name])
app.config.from_pyfile('application.cfg', silent=True)
FLASK_ENVは、export FLASK_ENV=development
なりで設定しておく。ここで言ってるのは、基本BaseConfigの内容を共通で使いつつも、環境(development/production)によって、それぞれ変数の内容を分けているということ。
os.environ.get('DATABASE_URL')
はHerkouでDATABASE_UELを自動でデータベースに引っ張ってくれるため本番はこれで設定しておく。
main/instance/application.cfg
SECRET_KEY='XXXXXXXXXXXXXXXXXXX'
ここでは、公にできないAPIキーを載せる。また、必ず.gitignore
に記載して公開しないようにしておく。
設定ファイルを読み込む
用意した設定ファイルを__init__.py
で使えるようにしておく。
# 下記の内容を追記する
from main.config import configure_app
app = Flask(__name__, instance_relative_config=True)
configure_app(app)
Herokuにデプロイ
gunicornとpsycpg2のインストール
Herokuにデプロイ、PostgreSQL
を使用するために2つのライブラリをインストールしておく。
$ pip install gunicorm
$ pip install psycopg2
Procfileに追記
herokuでアプリを動かすためのコマンドを書き足す。
web: gunicorn main:app --log-file -
インストールパッケージを用意
pip freeze
は便利なコマンドで仮想環境中に使ってるライブラリ情報を全部記してくれる。
$ pip freeze > requirements.txt
Herokuアプリにデプロイ
herokuの設定は割愛する。
$ heroku create flask-app
$ git push heroku master
$ heroku config:set FLASK_APP=main
$ heroku config:set FLASK_ENV=production
ここまでで、$ heroku open
すれば「Hello world!」が表示されているはず。
データベースの設定
モデルの作成
今回は、テストとしてUser
モデルを用意する。
from main import db
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
email = db.Column(db.String, unique=True)
def __repr__(self):
return '<User %r>' % self.name
Flask Migrate、SQL Alchemyのインストール
DBをマイグレートするために必要なライブラリをそれぞれインストールしていく。
$ pip install flask_migrate
$ pip install flask_sqlalchemy
モデルの読み込み
設定したモデルを読み込むための準備を__init__.py
に書き足していく。
# 下記を追記していく
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = SQLAlchemy(app)
migrate = Migrate(app, db)
db.init_app(app)
import main.models
マイグレーション
Flask Migrateコマンドの順に沿ってマイグレーションしていく。
$ flask db init
$ flask db migrate
$ flask db upgrade
これを実行すると、migrations
ファイルと、app.db
というデータベースが生成される。
Herokuでマイグレーション
インストールパッケージを用意
先ほどと同じように、新しくインストールしたライブラリをHerokuで使えるように設定していく。
$ pip freeze > requirements.txt
マイグレーション実行
ここが少しハマったのだが、Herokuにはローカルで生成したmigrations
ファイルごとサーバーにあげて、db init
やdb migrate
は実行しない。
$ heroku run flask db upgrade