Deployment
The backend ships as a Docker image whose entrypoint is start.sh, serving on port 8080. The same codebase runs in three roles: the API service, a migration job, and Celery workers.
Container
Build from the repository root:
Run it with an env file (see Environment configuration for the variables it expects):
start.sh loads .env in local mode, applies migrations via migrate.sh when a database is configured, then starts the server (Gunicorn with Uvicorn workers in production, Uvicorn otherwise).
Migrations
By default the API applies migrations on boot: start.sh calls migrate.sh, which runs alembic upgrade head. Setting SKIP_MIGRATIONS=true on the service suppresses that, for deployments that apply schema changes as a separate step. The Helm chart does this: templates/backend/migrate-job.yaml runs migrate.sh as a pre-sync Job and sets SKIP_MIGRATIONS=true on the backend pods (backend.migrations.job.enabled).
Make migrations backward compatible so a new revision can run before the new code is fully rolled out. To roll a schema change back:
Workers
Celery workers deploy as their own service from the worker image, sharing the broker and result backend (BROKER_URL, CELERY_RESULT_BACKEND). Scale workers independently of the API. See Background tasks.
Kubernetes
The production target is Kubernetes. .github/workflows/backend-k8s.yml builds the image, pushes it to Artifact Registry, and syncs ArgoCD; the Helm chart lives in charts/rhesis. Environment comes from the chart’s ConfigMap and existingSecret.
The image is a standard container, so it also runs on other platforms (AWS ECS, Azure Container Apps, plain Docker) given the same environment variables.
Operations
- Health —
GET /healthreturns{"status": "ok"}; use it as the container health check. - Logs — the application logs to stdout/stderr; set
JSON_LOGGER_ENABLED=truefor structured logs (see Architecture). - Rollback — redeploy the previous image; reverse migrations only if the new revision was not backward compatible.
- Secrets — supply
JWT_SECRET_KEY, database, and OAuth credentials through the platform’s secret manager, not the image.