はじめに
以下構成のバックエンド環境をFly.ioに初めてデプロイしてみたので、その時の手順を共有します。
- FastAPI(Dockerコンテナ)
- SQLAlchemy(ORM)
- Psycopg(PostgreSQL用のデータベースアダプター)
- Alembic(データベースのMigrationツール)
- Postgresql
特に、SQLAlchemy+psycopgを使ってFly.ioのPostgresqlに接続する場合、スムーズにいかなかったのでそのあたりのナレッジも残しておこうと思います。
対象読者
- Fly.ioにFastAPI + Postgresqlの環境をデプロイしたい方
- Fly.ioへのデプロイの流れや使い方をざっくり知りたい方
本記事の前提
開発環境
- MacOS 14.4.1
- Docker Desktop for Mac
デプロイ対象のFastAPIとPostgresqlのコンテナ
- FastAPIのDockerイメージはDockerfileから作成
FROM python:3.11-slim
RUN apt-get update && apt-get install -y \
build-essential && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN pip install poetry
RUN poetry install --no-interaction --no-ansi
EXPOSE 8000
CMD ["poetry", "run", "uvicorn", "--host", "0.0.0.0", "test_app.app:app"]
- FastAPIとPostgresqlは以下の
compose.yaml
で起動- Postgresqlへの接続文字列を環境変数で定義しています。
services:
db:
image: postgres
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_USER: test_user
POSTGRES_DB: test_db
POSTGRES_PASSWORD: test_password
ports:
- "5432:5432"
app:
image: test_app
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
depends_on:
- db
environment:
# psycopgアダプターを使用
DATABASE_URL: postgresql+psycopg://test_user:test_password@test_db:5432/app_db
volumes:
pgdata:
コンテナの環境変数は.env
等からロードするのが一般的ですが、本記事では便宜的にcompose.yamlにハードコーディングしています。
- データベースのマイグレーションファイル
- Alembicを使って以下のようにDBのマイグレーションファイルを管理しています。
.
├── alembic.ini
└── migrations
├── env.py
├── script.py.mako
└── versions
├── 71bfea98db2b_create_todo_table.py # <- マイグレーションファイル
└── 7c2f73b28d63_create_user_table.py # <- マイグレーションファイル
上記前提のもと、本記事では以下の内容を説明します。
- Fly.ioにFastAPIアプリケーションをデプロイする
- Postgresqlデータベースは、Fly.ioが提供するマネージドサービスを利用する
- デプロイしたFastAPIにssh接続してデータベースのマイグレーションを実行する
Fly.ioとは?
Fly.ioとは、アプリケーションをクラウド上で簡単に起動できるPaaS(Platform as a Service)型のプラットフォームです。
多くのプログラミング言語とフレームワークに対応しており、特にDockerコンテナを使用してのデプロイが可能です。
また、Fly.ioはPostgreSQLやRedisなど、アプリケーションで使用するデータベースも提供しています。
Fly.ioの無料プラン
Fly.ioは無料プランを提供しており、個人開発等でちょっと試しにデプロイしてみる環境にはちょうどいいです。
以下のリソースが無料で使えます。
- 最大3つのshared-cpu-1x 256MB VMs
- 3GBの永続ボリュームストレージ
- 合計160GBのアウトバウンドデータ転送
詳細は以下参照。
それではここからFly.ioにデプロイする手順を説明していきます。
①Fly.ioのアカウントを作成する
まずはFly.ioの以下ページからアカウントを作成しましょう。
アカウントを作成すると、以下のダッシュボード画面が表示されます。
クレジットカードの情報を登録する
無料枠が付いているものの、Fly.ioが提供するPostgresqlを利用するためにはクレジットカードの登録が必要になります。以下の手順で登録しておきましょう。1
- ダッシュボード画面上部に表示されている
Add a payment method to keep using our platform.
をクリック - 以下のHobby Planの下にある
Continue
をクリックしてカード情報を登録する
- ダッシュボードに$5.00の利用ができる旨、メッセージが表示されればOK
②flyctl
をインストールする
Fly.ioをローカル環境から操作するためのCLIアプリケーション flyctl
をインストールします。
インストール方法は、公式のインストールガイド を参照してください。
インストール後、以下のコマンドでflyctlのバージョンが表示されればOKです。
$ flyctl version
flyctl v0.2.50 darwin/arm64 Commit: b699e9.... BuildDate: 2024-05-08T14:04:18Z
③flyctl
からFly.ioにログインする
flyctl
からFly.ioを操作するための準備として、以下のコマンドでログインを行います。
$ flyctl auth login
Opening https://fly.io/app/auth/cli/223fascc23411973591eeaee63e2 ...
Waiting for session...
上記を実行するとブラウザウィンドウが開き、ログインを求められるので、作成したアカウントでログインします。
ログインに成功したら、ブラウザを閉じるとターミナルにログインが成功した旨のメッセージが表示されていればOKです。
...
Waiting for session... Done
successfully logged in as <ログインアカウントのメールアドレス>
以降、flyctl
を使ってアプリケーションのデプロイをしていきます。
④Fly.ioにAppsを作成する
デプロイする前に、まずは新しいアプリケーション(Fly.ioのApps
というもの)を以下のコマンドで作成します。
$ flyctl launch --no-deploy
-
flyctl launch
- Fly.io上に新しいアプリケーションを作成するコマンド
- アプリケーションの設定に必要な
fly.toml
ファイルなどがローカルに生成される
-
--no-deployオプション
- 実際のアプリケーションのデプロイは行わないようにするオプション
- こうすることで、アプリケーションの設定やコードを確認・修正してからデプロイすることができる
実行すると以下のメッセージが表示されます。
$ flyctl launch --no-deploy
Scanning source code
Detected a Dockerfile app
Creating app in /<youre-directory>
We're about to launch your app on Fly.io. Here's what you're getting:
Organization: <account name> (fly launch defaults to the personal org)
Name: fly-demo (derived from your directory name)
Region: Hong Kong, Hong Kong (this is the fastest region for you)
App Machines: shared-cpu-1x, 1GB RAM (most apps need about 1GB of RAM)
Postgres: <none> (not requested)
Redis: <none> (not requested)
Sentry: false (not requested)
? Do you want to tweak these settings before proceeding? (y/N)
上記の表示内容について、ポイントとしては以下です。
- カレントディレクトリにDockerfileが存在する場合、
flyctl
が自動的に検出してくれる(3行目) -
Organization:
以降は、作成するアプリケーションのデフォルト設定を示している- デプロイ先のリージョン (なぜかHong Kongになっている・・・)
- アプリケーションの実行マシン構成(
shared-cpu-1x, 1GB RAM
) - Postgres オプション(設定なし)
最後にDo you want to tweak these settings before proceeding? (y/N)
と聞かれますが、今回はデフォルト設定から変更したいので y
を入力します。
そうすると、再びブラウザウィンドウが開き、以下の画面が表示されるのでそれぞれ設定を変更していきます。
私の場合は、Fly.ioのお試し利用が目的だったのでマシンスペックや可用性はすべて最小構成にしました。
また、Postgresqlを使うのでDatabaseの設定を入力しています。
入力後、Confirm Settings
をクリックしてターミナルに戻ると、以下の通り、アプリケーションおよびPostgresqlを作成した旨のメッセージが表示されます。
Created app 'fly-demo-test' in organization 'personal'
Admin URL: https://fly.io/apps/fly-demo-test
Hostname: fastzeroapp.fly.dev
Creating postgres cluster in organization personal
Creating app...
...省略
Postgres cluster fly-demo-test-postgres created
Username: postgres
Password: YIawXXplW2rRe2b
Hostname: fly-demo-test-postgres.internal
Flycast: fdaa:9:4169:0:1::2
Proxy port: 5432
Postgres port: 5433
+ Connection string: postgres://postgres:YIaPPtXCRrRe2b@fly-demo-test-postgres.flycast:5432
...省略
Postgres cluster fly-demo-test-postgres is now attached to fly-demo-test
The following secret was added to fly-demo-test:
+ DATABASE_URL=postgres://fly_demo_test:cQv0vvfasf7FM@fly-demo-test-postgres.flycast:5432/fly_demo_test?sslmode=disable
Postgres cluster fly-demo-test-postgres is now attached to fly-demo-test
? Create .dockerignore from .gitignore files? (y/N)
上記の差分として表示している箇所は、作成したPostgresqlデータベースへの接続文字列です。
この情報はFly.ioのWeb画面でも閲覧できない機密情報になるため、この情報は大切に保管し、共有はしないようにしましょう。
また、最後の質問(? Create .dockerignore from .gitignore files? (y/N)
)については、.dockerignore
が必要であればy
にしましょう。
? Create .dockerignore from .gitignore files? (y/N) Yes
Created <src-path>/.dockerignore from 4 .gitignore files.
Wrote config file fly.toml
Validating <src-path>/fly.toml
✓ Configuration is valid
Your app is ready! Deploy with `flyctl deploy`
上記の通り、アプリケーションをデプロイする準備が整ったようです🎉
また、カレントディレクトリを見てみると、作成したアプリケーションの構成情報(fly.toml
)ファイルが作成されていると思います。
⑤環境変数をFly.ioのSecrets
に登録する
アプリケーション内で利用している環境変数がある場合、デプロイする前にFly.io上で読み込める状態にする必要があります。
これを実現するために、Fly.ioではSecrets
という機能を提供しています。
Secrets
を使用すると、デプロイしたアプリに資格情報などを環境変数として渡すことができます。
どうやってSecretsを登録するかというと、
flyctl
の secrets set
コマンドを使って登録することができます。
$ fly secrets set MY_SECRET_NAME="test secret"
SQLAlchemy + PsycopgでPostgresqlに接続する方法
本記事では、元々compose.yaml
内で定義していたデータベースの接続文字列 DATABASE_URL
を手順④で払い出された接続文字列に変更し、その値をアプリケーションからロードできる状態にします。
登録する前に、まずはflyctl secrets list
で現在登録されている環境変数を確認してみます。
$ flyctl secrets list
NAME DIGEST CREATED AT
DATABASE_URL eb0aac24db6ab082 1h10m ago
実は上記の通り、手順④を実行したときにDATABASE_URLが環境変数として登録されています。
内容は以下の値です。
Connection string: postgres://postgres:YIaPPtXCRrRe2b@fly-demo-test-postgres.flycast:5432
ただし、SQLAlchemyとPsycopgを使ってPostgresqlに接続している場合、上記の接続文字列を有効な値として認識してくれません。
元々、compose.yamlのDATABASE_URL
で定義していたようにプレフィックスの部分をpostgresql+psycopg
に修正する必要があります。
- postgres://postgres:YIaPPtXCRrRe2b@fly-demo-test-postgres.flycast:5432
+ postgresql+psycopg://postgres:YIaPPtXCRrRe2b@fly-demo-test-postgres.flycast:5432
以下のコマンドで環境変数DATABASE_URL
を修正した値で上書き登録できます。
$ flyctl secrets set DATABASE_URL=postgresql+psycopg://postgres:YIaPPtXCRrRe2b@fly-demo-test-postgres.flycast:5432
Secrets are staged for the first deployment
⑥アプリケーションのデプロイ
デプロイする準備が整ったので、flyctl deploy
コマンドでアプリケーションをデプロイします。
$ fly deploy --local-only --ha=false
-
--local-only
- このオプションをつけると、デプロイ処理(コンテナのビルド等)がローカル環境で実行されます。
- このオプションを指定しない場合、デプロイ処理はFly.io上で実行されますが、ローカル環境でテストやデバッグをしたい場合にこのオプションを使用します。
-
--ha=false
- 高可用性デプロイを有効にするオプションです。アプリケーションが複数のインスタンスで立ち上がり、障害時に自動でフェイルオーバーしてくれます。
- 今回は無料枠内で検証したいので本機能をFalseで無効化しています。
上記コマンドを実行すると、以下のようにDockerイメージのビルドが実行され、その後Fly.ioにデプロイされます。
$ fly deploy --local-only --ha=false
==> Verifying app config
Validating <your-directory>/fly.toml
✓ Configuration is valid
--> Verified app config
==> Building image
==> Building image with Docker
--> docker host: 25.0.5 linux aarch64
[+] Building 51.0s (12/12) FINISHED
...省略
--> Building image done
==> Pushing image to fly
The push refers to repository [registry.fly.io/fly-demo-test]
8c65950a7b44: Pushed
afe5e98a69a7: Pushed
2ff1765ea85f: Pushed
52664eb4ef6b: Pushed
b0190595c83a: Pushed
67704d8b406c: Pushed
216328af4e79: Pushed
238975b59c5f: Pushed
3069e121245c: Pushed
146826fa3ca0: Pushed
5d4427064ecc: Pushed
deployment-01HY09TSQNFP1FB83CXDR9H3SZ: digest: sha256:8c0297ce2be1e15c1b513ff41a05c613cb5c01d590db5c3200dd59df15009358 size: 2633
--> Pushing image done
image: registry.fly.io/fly-demo-test:deployment-01HY09TSQNFP1FB83CXDR9H3SZ
image size: 812 MB
Watch your deployment at https://fly.io/apps/fly-demo-test/monitoring
Provisioning ips for fly-demo-test
Dedicated ipv6: 2a09:8280:1::35:b49f:0
Shared ipv4: 66.241.125.58
Add a dedicated ipv4 with: fly ips allocate-v4
This deployment will:
* create 1 "app" machine
No machines in group app, launching a new machine
Finished launching new machines
-------
NOTE: The machines for [app] have services with 'auto_stop_machines = true' that will be stopped when idling
-------
Checking DNS configuration for fly-demo-test.fly.dev
Visit your newly deployed app at https://fly-demo-test.fly.dev/
上記メッセージの最後の方に、アプリケーションのデプロイに関する重要な情報が示されています。
- 監視URL(https://fly.io/apps/your-app-name/monitoring)
- コンテナのログを閲覧できる
- アプリケーションにアクセスするためのURL(https://your-app-name.fly.dev/)
監視URLにアクセスすると、以下の通りFastAPIが起動していることが確認できると思います🎉🎉
⑦アプリケーションにssh接続してAlembicでデータベースのマイグレーションを実行する
ただし、今の状態だとFly.ioに作成したPostgresqlはテーブル情報を保持していません。
そのため、DBのマイグレーションファイルを使ってPostgresqlにテーブルを作成する必要があります。
Fly.ioではデプロイしたアプリケーションにssh接続し、任意のコマンドを実行することができます。
flyctl ssh console -a <app-name> -C "実行するコマンド"
本コマンドを使ってAlembicのマイグレーションを実行します。
$ flyctl ssh console -a fastapi-zero -C "alembic upgrade head"
Connecting to fdaa:9:4109:a7b:b4f1:12d8:1709:2... complete
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 7c2f73b28d63, create user table
INFO [alembic.runtime.migration] Running upgrade 7c2f73b28d63 -> 71bfea98db2b, create todo table
その後、デプロイしたFastAPIの
swagger UI(https://your-app-name.fly.dev/docs) 等にアクセスし、DBに対してCRUD操作が行えることを確認できればOKです。
⑦アプリケーションの削除
デプロイしたアプリケーションとPostgresqlを削除したい場合、それぞれ以下のコマンドで削除できます。
# アプリケーションの削除
$ fly apps destroy <app-name>
# Postgresqlの削除
$ fly apps destroy <db-name>
さいごに
以上、FastAPI/SQLAlchemy/psycopg/Alembic/PostgreSQLの組み合わせをFly.ioにデプロイする手順の紹介でした。
この組み合わせがピンポイントでハマる人がいるかは微妙ですが、誰かの役に立ったら嬉しいです。
Fly.ioを使ってみた感想として、デプロイ操作は直感的でやりやすかったのですが、Fly.ioのWeb画面がもっさりしているのが少し気になりました。
-
クレジットカードを登録しない状態でdeployすると以下のエラーが発生します。
Error: We need your payment information to continue! Add a credit card or buy credit: https://fly.io/dashboard/<アカウント名>/billing ↩