MAEL doesn’t require Kubernetes to run in production — the codebase and this documentation deliberately support two paths, and you should pick the smaller one until you have a concrete reason not to.

Docker Compose (VPS)

One machine, docker compose up, a reverse proxy for TLS. Right choice for a pilot, a small client base, or anyone who doesn’t want to operate a cluster.

Kubernetes

Helm + ArgoCD GitOps, horizontal pod autoscaling per queue, a production Vault Raft cluster. Right choice once you’re operating at a scale where per-queue autoscaling and zero-downtime rolling deploys earn their operational cost.

What’s identical either way

  • The application images — the same docker/api.Dockerfile build (API and every Celery worker queue, differing only by container command) runs unmodified under Compose or Kubernetes
  • Database migrationsalembic upgrade head, same command, same migration files
  • Secrets — Vault in AppRole mode; production Settings validation refuses to boot with a dev token or a missing AppRole role ID regardless of orchestrator
  • Observability — the same LGTM stack (Prometheus/Grafana/Loki/Tempo) and the same alert rules; see Observability

What differs

Production settings, regardless of path

APP_ENV=production triggers strict boot-time validation (core/config/settings.py) that fails loudly rather than degrading silently:
  • app_debug and api_docs_enabled must be false
  • vault_approle_role_id must be set; vault_dev_token must be unset
  • redis_url/celery_broker_url/celery_result_backend must not be localhost
  • api_public_base_url must not be localhost (breaks every OAuth callback otherwise)
  • cors_origins must not contain a wildcard or localhost entry
A production process that’s missing any of these simply won’t start — there’s no “boots fine, breaks at request time” failure mode here.

Docker / VPS

Kubernetes