技術メモなど

ほぼ自分用の技術メモです。

Python + Flask + Heroku + Heroku Postgres で無料の範囲内の Web アプリを公開する手順メモ

Heroku で Flask のアプリを動かしたりPostgreSQL を無料の範囲内で使う手順のメモです。(無料版の制限事項は Heroku を使って無料でアプリを開発 参照。)

事前に Heroku のアカウントを作成しておく必要があります。なお、無料の範囲内でも PostgreSQL を使いたい場合はクレジットカードの登録が必要です。 Heroku のアカウントを作成後、 Heroku Dashboard から Account Settings - Billing に遷移すればクレジットカードを登録できます。

Heoroku CLI のインストール

Heroku を使う時、ほとんどの操作がダッシュボードから行えるとは思いますが、コマンドで操作できるようにしておいた方が都合が良い場合もあるので Heroku CLI をインストールしておきます。 Heoroku Dev Center で OS 別のインストール方法が記載されているので、環境に合った方法でインストールできます。自分は tarball を /usr/local/lib/heroku に展開し、 /usr/local/bin/heroku にシンボリックリンクを貼るようにしています。

ローカルでの下準備 (Git)

Heroku でアプリを公開するには、アプリを Git で管理することが必要です。アプリの作成と更新は、 Heroku のリモートリポジトリに push することで行うことになります。例として、次のような Python の Flask で作成したアプリを Heroku で公開することにします。

$ mkdir yourprojectname
$ cd ./yourprojectname
$ touch hello.py
$ touch requirements.txt

hello.py の中身は Quickstart — Flask Documentation (1.x.x) のまんまです。

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'


if __name__ == "__main__":
    app.run()

requirements.txt にはインストールしたいライブラリを記載します。

flask

ローカルでアプリが動くかテストします。 requirements.txt から Flask をインストールし、起動してみます。起動する前に環境変数の設定も必要です。

$ pip install -r requirements.txt
$ export FLASK_APP=hello.py
$ flask run

ブラウザで http://localhost:5000/ にアクセスし、 Hello World! とブラウザに表示されれば成功です。

テストに成功したら、このアプリを Git 管理下に置きます。

$ git init
$ git add .
$ git commit -m "first commit."

Heroku の設定

Heroku にログイン

ここまでできたら Heroku CLI でアプリを公開する下準備をします。まずは Heroku にログインします。

$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening Browser to https://cli-auth.heroku.com/auth/cli/browser/hogefuga

適当なキーを押すとブラウザが起動して Heroku のログイン画面が表示されるのでログインします。ログインに成功するとターミナルにメッセージが表示され、以降 Heroku の操作が可能になります。

Logging in... done
Logged in as hoge@example.com

Heroku でアプリの作成

Heroku でアプリを作成するのはブラウザから GUI でできますが、 Heroku CLI で Heroku にアプリを作成すると Git リモートリポジトリの設定を自動で行ってくれるのでコマンドから行います。

$ heroku create yourprojectname
$ git remote -v
heroku  https://git.heroku.com/yourprojectname.git (fetch)
heroku  https://git.heroku.com/yourprojectname.git (push)

作成したアプリが無料版になっているか確認します。 Heroku Dashboard から作成したアプリの管理画面を開き、Overview にて Dyno Formation が This app is using free dynos となっていれば無料版です。

Heroku で環境変数の設定

Quickstart — Flask Documentation (1.x.x) に沿って Flask を動かすためには環境変数の設定が必要なので、 Heroku CLI で行います。

$ heroku config:set FLASK_APP=hello.py
$ heroku config:get FLASK_APP
hello.py

アプリの公開

ここまで準備ができたら、 Heroku のリモートリポジトリに push するだけでアプリが公開できます。

$ git push heroku main

push が成功したら、ブラウザで https://yourprojectname.herokuapp.com/ にアクセスします。 Hello World! とブラウザに表示されると思います。

Web サーバに gunicorn を使う場合

Deploying Python Applications with Gunicorn | Heroku Dev Center を参考に、Heroku に gunicorn をインストールし、 Procfile というテキストファイルを作成します。

$ touch Procfile
$ echo "web: gunicorn hello:app --log-file -" >> Procfile

requirements.txt に gunicorn を追加します。

$ echo "gunicorn" >> requirements.txt
$ pip install -r requirements.txt

gunicorn でアプリが動くことを確認します。

$ gunicorn hello:app --log-file -

ブラウザで http://localhost:8000 にアクセスしてエラーなくコンテンツが返ってこれば成功です。

変更をコミットしたら Heroku リモートリポジトリに push します。これで Web サーバが gunicorn になります。

PostgreSQL の利用 (Heroku Postgres)

データベースの作成

Heroku Postgres という add-ons を使用することで PostgreSQL を使用できます。無料版であれば10,000レコードまでの制限があります。(無料版でもクレジットカードの登録が必要なことに注意。)

これも Heroku CLI から行います。

heroku addons:create heroku-postgresql:hobby-dev

Heroku Dashboard から作成したアプリの管理画面を開き、 Overview にて Installed add-ons に Heroku Postgres が Hobby Dev となっていれば無料版で PostgreSQL が作られています。(念のため Installed add-ons の横に $0.00/month と表示されていることも確認しましょう。)

データベースの管理

Heroku CLIpsql が使えます。

$ heroku pg:psql 

データベースへの接続

上記までの手順で自動的に Heroku 上の環境変数 DATABASE_URL に PostgreSQLURI がセットされるので、アプリからこれを PostgreSQL の接続情報として使うようにすればよいです。

ちなみに Python なら psycopg2 というライブラリを使うと簡単でした。

import os

import psycopg2

from flask import Flask, g


app = Flask(__name__)

# 環境変数から PostgreSQL の URI を取得
DATABASE_URL = os.environ.get("DATABASE_URL")

def get_pg_conn():
    """ PostgreSQL へ接続 """
    if not hasattr(g, "pg_conn"):
        g.pg_conn = psycopg2.connect(DATABASE_URL)
    return g.pg_conn


@app.teardown_appcontext
def close_pg_conn(error):
    """ エラーが発生したら PostgreSQL への接続を閉じる """
    if hasattr(g, "pg_conn"):
        g.pg_conn.close()


@app.route('/')
def hello_world():
    conn = get_pg_conn()
    cursor = conn.cursor()

    """
    何らかの PostgreSQL の処理
    """

    return 'Hello, World!'


if __name__ == "__main__":
    app.run()

以上で無料の範囲内で Heroku の PostgreSQL を使うことができます。

私はこれで旭川市のオープンデータを使ったアプリを無料でいくつか運用しています。

おまけ

PostgreSQL を無料版から有料版に移行する場合、新たに Heroku Postgres を追加し、アプリからのデータベース接続の向きを追加した Heroku Postgres へ向ける必要があります。

無料版 (hobby-dev) で10,000レコードを超えると、 Heroku から「7日間以内に上位プランに変更しないと INSERT 権限停止するよ(意訳)」とメールが来るのですが、 旭川市新型コロナウイルス感染症非公式オープンデータ が10,000レコードを超えてしまったので、一番安い hobby-basic ($9.00/month) に変更しました。

$ heroku addons:create heroku-postgresql:hobby-basic

追加した hobby-basic の環境変数を確認します。

$ heroku pg:info
=== HEROKU_POSTGRESQL_( ここが環境によって異なる )_URL
( 以下省略 )

一旦アプリをメンテナンスモードにしてから無料版データベースの内容を今回追加したデータベースへコピーします。

$ heroku maintenance:on
$ heroku pg:copy DATABASE_URL HEROKU_POSTGRESQL_( ここが環境によって異なる )_URL

環境変数 DATABASE_URL を hobby-basic の方の URI を返すようにしたいので、こちらをプライマリデータベースに昇格させます。

$ heroku pg:promote HEROKU_POSTGRESQL_( ここが環境によって異なる )_URL
$ heroku config:get DATABASE_URL
( 以下に hobby-basic の URI が表示されることを確認する )

最後にメンテナンスモードを解除して終了です。

$ heroku maintenance:off