Skip to content

Helm

The Helm chart in charts/codex-pooler deploys the same Codex Pooler release image into Kubernetes. It separates web traffic, background work, scheduled work, and migration work so each role can scale and restart on its own.

Use this page as the public shape of the chart. Keep environment-specific secrets, private image repository names, internal hostnames, and operational evidence out of values files and public docs.

The chart has four release roles:

  • app, serves HTTP with OBAN_MODE=web and PHX_SERVER=true
  • oban.worker, runs background jobs with OBAN_MODE=worker
  • oban.scheduler, runs scheduled jobs with OBAN_MODE=scheduler
  • migrations, runs release migrations before app rollout when enabled

All roles use the same image repository and tag. Only the app role serves HTTP. Worker, scheduler, and migration pods don’t expose the Phoenix endpoint.

Set an explicit immutable image tag for real deployments. Don’t rely on latest outside local scaffolding or temporary testing.

image:
repository: ghcr.io/icoretech/codex-pooler
tag: v0.1.0
pullPolicy: IfNotPresent

The chart appVersion is informational. Treat image.tag as the deployable release version.

By default, the chart expects an existing Kubernetes Secret:

secrets:
create: false
existingSecret: codex-pooler-secrets

That secret must provide the release values needed before Codex Pooler can read database-managed settings:

  • database-url
  • secret-key-base
  • totp-encryption-key
  • totp-key-version
  • upstream-secret-key
  • upstream-secret-key-version

Don’t put upstream access tokens, Pool API keys, MCP tokens, cookies, auth.json, SMTP passwords, or raw client payloads into chart values.

Set the public host through chart values:

config:
host: pooler.example.com
ingress:
enabled: true
hosts:
- host: pooler.example.com
paths:
- path: /
pathType: Prefix

Public client examples should use https://pooler.example.com as the deployed base URL.

The default topology is conservative:

app:
enabled: true
replicaCount: 1
oban:
worker:
enabled: true
replicaCount: 1
scheduler:
enabled: true
replicaCount: 1
migrations:
enabled: true

The migration hook runs database migrations and imports the vendored OpenAI pricing feed. The scheduler keeps scheduled background work separate from request-serving pods.

Keep the web app at one replica unless you intentionally configure the multi-replica websocket topology.

Backend websocket sessions own a live upstream websocket inside an app pod. Multiple app replicas need clustering, owner-forwarding, and the explicit unsafe topology acknowledgement:

clustering:
enabled: true
query: <headless-service-dns-name>
app:
replicaCount: 2
websocketContinuity:
ownerForwarding:
enabled: true
allowUnsafeMultiReplica: true

Only set allowUnsafeMultiReplica: true after you have verified the topology you are running. Without that proof, keep app.replicaCount: 1.

Render manifests locally before applying them:

Terminal window
helm template codex-pooler ./charts/codex-pooler \
--set image.repository=ghcr.io/icoretech/codex-pooler \
--set image.tag=v0.1.0 \
--set config.host=pooler.example.com \
--set ingress.enabled=true \
--set ingress.hosts[0].host=pooler.example.com

Inspect the output for the expected app, worker, scheduler, migration, Secret reference, Service, and Ingress resources. The rendered app Deployment should serve HTTP. Worker, scheduler, and migration resources should not.

For install or upgrade, provide your production values file from a private path:

Terminal window
helm upgrade --install codex-pooler ./charts/codex-pooler \
--namespace codex-pooler \
--create-namespace \
--values ./values.production.yaml

Keep values.production.yaml private if it contains secret names, internal DNS names, ingress details, or environment-specific settings.