Kubernetes
What exists for Kubernetes today, and how to map the Compose deployment onto it yourself.
No Helm chart yet
OCI v0.10.2 ships no Helm chart, Kustomize base or Kubernetes manifests. The supported deployment is Docker Compose. A first-party Helm chart, with a migration job before each rollout, rolling updates, disruption budgets and autoscaling on OCI's metrics, is on the roadmap for v0.11.
The two images run on Kubernetes without changes. If you build your own manifests, map the Compose services like this:
| Compose | Kubernetes |
|---|---|
web | A Deployment (port 8080) behind a Service and your Ingress or Gateway. Point it at the API Service with API_UPSTREAM_HOST (such as oci-api) and API_UPSTREAM_PORT (3000); the bundled Caddyfile also reads API_UPSTREAM (oci-api:3000). |
api | A Deployment (port 3000) and a Service. Environment from a Secret (DATABASE_URL, AUTH_SECRET, ENCRYPTION_KEY) and a ConfigMap (APP_URL, REDIS_URL, NODE_ENV=production, RUN_MIGRATIONS=false). |
migrate | A Job running node dist/migrate.js with the API image, before each rollout. |
postgres, redis | Your managed or operator-run PostgreSQL 17 and Redis. |
storage_data volume | Not needed: use S3-compatible storage, so every replica sees every file. |
Points that matter on Kubernetes:
- Probes. API readiness:
GET /api/health/ready(checks the database; 503 when it cannot reach it). Liveness:GET /api/health/live. The web container serves the app on 8080; probe/there. - Migrations. Run the migration Job to completion before rolling out a new API version, and start the API with
RUN_MIGRATIONS=false. Several replicas starting withRUN_MIGRATIONS=trueare safe too (an advisory lock serialises them), but the Job makes rollouts predictable. - Database connections. Point
DATABASE_URLat PostgreSQL directly or through a session-mode pooler, never transaction-mode PgBouncer. Budget the pool plus one connection per running background job, per replica. - The web proxy finds API pods by re-resolving
API_UPSTREAM_HOSTevery ten seconds; a headless Service lets it balance across pods itself, while a normal ClusterIP Service balances for it. - Metrics are served on each API pod's port 3000 at
/metricswhenMETRICS_TOKENis set; scrape pods directly. - The API image runs as a non-root user (
oci) and writes files under/data/storageonly with the local driver. - Ingress: send every path,
/apiincluded, to the web Service; do not route/apistraight to the API around it. Disable response buffering and raise timeouts for/api, and keep the artifact frame headers intact. - Client addresses. Set
TRUSTED_PROXIESon the web Deployment to the ingress controller pods' range (or the cluster's pod CIDR), separated by spaces, so sessions, the audit log and the sign-in limit see each person's address instead of the ingress's. See Behind another proxy or an ingress. - Images are
linux/amd64only. - Upgrades follow the same procedure as Compose: Upgrades.