FastAPI + PostgreSQL service designed as a DevOps portfolio project: containerized, tested, Kubernetes-ready, Terraform-managed, and CI/CD automated.
This repository demonstrates practical DevOps engineering skills, not just API coding:
- Async Python service with real database interactions.
- Reproducible Docker image with multi-stage build and non-root runtime.
- Kubernetes deployment with probes, resource limits, secrets, and persistent storage.
- Terraform-based infrastructure definition for cluster resources.
- CI pipeline with lint + smoke + PostgreSQL integration test.
- Manual-gated deployment workflow to control costs and risk.
- Backend: FastAPI, asyncpg, Pydantic
- Database: PostgreSQL
- Containerization: Docker, Docker Compose
- Orchestration: Kubernetes (Minikube-friendly manifests)
- IaC: Terraform (Kubernetes provider)
- CI/CD: GitHub Actions + GHCR
flowchart LR
User[Client] --> API[FastAPI Service]
API --> DB[(PostgreSQL)]
subgraph CI/CD
GH[GitHub Actions]
GH --> Test[Lint + Tests]
GH --> Build[Build & Push Image to GHCR]
GH --> Deploy[Manual Deploy Job]
end
Build --> Registry[(GHCR)]
Deploy --> K8s[Kubernetes Cluster]
Registry --> K8s
K8s --> API
K8s --> DB
If you include this on your resume, these are the strongest talking points:
- Implemented secure secret flow from GitHub Secrets to Kubernetes Secret references.
- Hardened workloads with startup/readiness/liveness probes and resource governance.
- Added PVC-backed Postgres storage instead of ephemeral pod volume.
- Built quality gates in CI with real integration tests against PostgreSQL.
- Switched deployment to manual trigger to avoid unintended cloud spend.
- Set environment values:
cp .env.example .env
# edit DB_PASSWORD in .env- Start services:
docker-compose -f docker/docker-compose.yml up --build- Initialize database schema:
docker exec -i $(docker-compose -f docker/docker-compose.yml ps -q db) \
psql -U postgres -d server_management < sql/schema.sql- Open API docs:
- Swagger: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
uv venv
source .venv/bin/activate
uv pip install --python .venv/bin/python --requirement requirements.lock
createdb server_management
psql server_management < sql/schema.sql
uvicorn app.main:app --reload- Build image in Minikube:
minikube image build -f docker/Dockerfile -t server-management-api:latest .- Create DB secret:
kubectl create secret generic server-management-db \
--from-literal=DB_NAME=server_management \
--from-literal=DB_USER=postgres \
--from-literal=DB_PASSWORD=change_me \
--from-literal=POSTGRES_DB=server_management \
--from-literal=POSTGRES_USER=postgres \
--from-literal=POSTGRES_PASSWORD=change_me- Apply manifests:
kubectl apply -f k8s/- Initialize schema:
kubectl exec -i deploy/postgres -- \
psql -U postgres -d server_management < sql/schema.sql- Access service:
kubectl port-forward svc/server-api 8000:8000Current manifests include:
- Startup/readiness/liveness probes for API and Postgres.
- CPU/memory requests and limits.
- Secret-based credentials (no plaintext passwords in manifests).
- Restricted container privileges (
allowPrivilegeEscalation: false, dropped caps). RuntimeDefaultseccomp profile.- Postgres persistence using PVC (
postgres-data).
Terraform under terraform/ provisions Kubernetes objects equivalent to the manifests.
cd terraform
terraform init
terraform plan -var="db_password=change_me" -out=tfplan
terraform apply tfplanWorkflow file: .github/workflows/ci-cd.yml
- On push/PR to
main: run lint + tests. - Deploy job: manual trigger only (
workflow_dispatch). - Image publish: GHCR.
- Cluster access:
KUBECONFIG_BASE64secret.
Required GitHub Secrets:
KUBECONFIG_BASE64DB_NAMEDB_USERDB_PASSWORD
GET /healthGET /servers/GET /servers/{server_id}POST /servers/PUT /servers/{server_id}DELETE /servers/{server_id}
Example create request:
curl -X POST "http://localhost:8000/servers/" \
-H "Content-Type: application/json" \
-d '{
"hostname": "webserver.local.lan",
"configuration": {"cpu_cores": 8, "ram_gb": 32},
"datacenter_id": 1
}'app/ FastAPI app and routers
k8s/ Kubernetes manifests
docker/ Dockerfile and compose config
terraform/ Terraform configuration
sql/ Schema and seed data
.github/workflows/ CI/CD pipeline
- Logging is configurable via environment variables.
- Integration tests run when
RUN_INTEGRATION_TESTS=1. - Dependency install is managed via
uvandrequirements.lock. - Local test command:
uv run --python .venv/bin/python pytest -q- Add coverage threshold enforcement in CI.
- Add NetworkPolicy manifests for namespace-level traffic control.
- Add OpenTelemetry/Prometheus instrumentation for runtime observability.