Deploy FastAPI with PostgreSQL on Sealos
Deploy the protected FastAPI Tasks API with PostgreSQL on Sealos using SQLAlchemy 2, psycopg 3, Alembic 0001, migration-first readiness, and restart persistence.
This second guide keeps the same FastAPI Tasks API and replaces process-local
storage with PostgreSQL. The protected
stage-2-postgresql
tag uses SQLAlchemy 2, the explicit psycopg 3 dialect, and Alembic revision
0001.
Start with the Stage 1 deployment guide if you still need the initial Sealos plugin and Runtime Truth workflow. Continue to the production guide after this stage proves migration order and persistence.
Key takeaways
| Question | Verified answer |
|---|---|
| Which connection key does the app read? | DATABASE_URL |
| Which library opens PostgreSQL connections? | SQLAlchemy 2 using postgresql+psycopg |
| Who creates the schema? | Alembic revision 0001 |
| What blocks readiness? | An unreachable database or missing tasks schema |
| What proves durability? | Public create, process replacement, and exact public readback |
Prerequisites
You need:
- The Sealos plugin installed and authenticated
- Git, Python 3.12,
uv,curl, andkubectl - Access to a Sealos workspace that can create application and database resources
- A fresh PostgreSQL database generated by the deployment plan
The protected README uses PostgreSQL 17 for its source integration harness.
The accepted current Sealos practice generated a KubeBlocks
postgresql-16.4.0 Cluster from the installed plugin's mandatory database rule.
Keep both facts in context: PostgreSQL 17 is the source prerequisite, while the
generated Cluster version is the actual current Sealos runtime selection.
Architecture
The application remains responsible for /health, generated /docs, and
/tasks CRUD. Alembic owns the schema. PostgreSQL owns durable task rows across
application process replacement.
Step 1: Inspect the database-ready source
Clone the protected stage:
Reproduce the locked environment and runtime export:
The source reads one SQLAlchemy URL:
Keep the actual value in a Sealos Secret. The tracked production migration
contract reads key url from Secret sealos-fastapi-postgresql.
Inspect the migration sequence locally against an empty database:
The first upgrade records revision 0001; the final command proves the same
head is repeatable.
Protected FastAPI Stage 2 source showing SQLAlchemy 2, psycopg 3, DATABASE_URL, and Alembic revision 0001Step 2: Ask Sealos for FastAPI and PostgreSQL together
From the protected checkout, use Codex CLI:
Or use Claude Code:
The request should produce one resource plan for the application and database. Review the plan before DEPLOY so the database URL source, migration order, and public application path remain explicit.
Step 3: Review the generated resource plan
The fresh accepted plan contained these functional parts:
- A FastAPI StatefulSet, Service, HTTPS Ingress, and App resource
- A KubeBlocks PostgreSQL 16.4 Cluster and its generated Service
- A generated connection Secret used as the source for
DATABASE_URL - A ConfigMap for the protected source bootstrap
- A one-shot migration Job
- Run-owned ServiceAccount, Role, and RoleBinding resources
The plugin completed strict artifact checks, the database quality gate, and a server-side dry run before resource creation. Review generated values in place and keep the connection URL redacted from output and retained logs.
Redacted current Sealos plan for the FastAPI app, KubeBlocks PostgreSQL 16.4, Service, Ingress, Secret, and migration JobStep 4: Migrate before accepting readiness
The source contract validates and applies deploy/migration-job.yaml before the
application is accepted:
Before migration, the practiced app returned 503:
Two independently created migration Jobs then reported Complete=True at
Alembic 0001. The repeat ran with a restricted security context and reached
the same revision. Only after that result did schema-aware /health return
200.
Fresh and repeated FastAPI migration Jobs reaching Complete True at Alembic 0001 after the unmigrated 503 stateStep 5: Validate the database behavior suite
Point both source test boundaries at a migrated test database:
The accepted clean practice completed 24 PostgreSQL tests in 203.23 seconds. One upstream Starlette deprecation warning was classified as non-blocking. The tests observe health, docs, CRUD, validation, stable errors, and persistence through public HTTP interfaces.
Step 6: Verify public CRUD
Check readiness and documentation on the generated domain:
Create and read a task:
The accepted practice returned 201 for create and 200 for read.
Step 7: Prove process-restart persistence
Restart the generated application workload while retaining the database:
Read the same task after the replacement process becomes Ready:
The fresh practice read task 1 back with status 200 after process
replacement and again after a restricted UID/GID rollout. Its final 85-second
runtime window had zero active failures, zero log findings, and zero restart
delta.
Public FastAPI task remaining readable after process replacement and restricted rollout against the same PostgreSQL databaseReadiness contract
Use /health as a schema-aware gate:
200 {"status":"ok"}means PostgreSQL is reachable and the tasks schema exists.503 {"detail":"Database is not ready"}means the URL, server, or schema still needs attention.
Application startup does not create tables. Keep migration completion as an explicit prerequisite for readiness and scaling.
Common failures
/health stays at 503
Check that DATABASE_URL comes from the generated database Secret, the
KubeBlocks Cluster is Running, and the migration Job is Complete at 0001.
The migration Job cannot connect
Confirm the Job and application consume the same connection source. Keep the URL out of command history and inspect Secret references by name and key.
Tests report one migration failure
The protected suite uses both DATABASE_URL and TEST_DATABASE_URL. Set both
for the test process, and point them at the migrated test database.
Tasks disappear after restart
Confirm the restarted process still reads the same generated DATABASE_URL.
A fresh local URL or a different database creates a separate task set.
Completion checklist
- The checkout points at
stage-2-postgresql - Lock reproduction and runtime export checks pass
- The plan contains app, PostgreSQL, Secret, Service, Ingress, and Job resources
- The generated PostgreSQL version is reviewed as runtime truth
- The migration Job reports
Complete=Trueat0001 - A repeated migration remains at
0001 - Schema-aware
/healthreturns200 - Public create and read requests succeed
- The same task survives application process replacement
- Runtime logs and restart deltas remain clean
Continue with FastAPI Production Deployment on Sealos for immutable images, hardened replicas, release logs, and rollback recovery.
FAQ
Previous
How to Deploy FastAPI on Sealos in 5 Minutes
Next
FastAPI Production Deployment on Sealos
Keep building
Continue this Sealos path
Unify Your Entire Workflow.
Code in a ready-to-use cloud environment, deploy with a click. Sealos combines the entire dev-to-prod lifecycle into one seamless platform. No more context switching.
Explore with AI
Get AI insights on this article