Install the chart
The default setup uses PostgreSQL as its datastore, NATS JetStream as its event bus, and the datastore-backed secret provider. It needs these three values:
Generate an encryption key and install the chart:
existingSecret to a Kubernetes
Secret that contains PERSISTENCE_DSN, NATS_URL, and ENCRYPTION_KEY. Add
AUTH_PAT when using an external Zitadel provider. When existingSecret is
set, the chart does not create a Secret.
If you use AWS Secrets Manager instead of the datastore-backed provider, you
do not need ENCRYPTION_KEY. See
Configuration for provider settings.
Resources
Server
The server Deployment serves the API and web application through a Service on port 8080. It starts with one replica. The chart can also create an Ingress, HorizontalPodAutoscaler, and PodDisruptionBudget.Control plane
The control-plane Deployment runs the scheduler, dispatcher, tracker, and reaper. It starts with one replica and exposes health endpoints on port 8081. Its ServiceAccount has namespaced access to the Kubernetes Jobs it creates and removes.Database migrations
A post-install and post-upgrade hook runs migrations with the server image. The migration Job waits up to five minutes for PostgreSQL and retries failed attempts up to six times. Setpersistence.migrate: false if you manage
migrations separately.
Rollouts and health checks
Both Deployments annotate their pods with checksums of the rendered ConfigMap and chart-managed Secret. Changing either resource through Helm triggers a rollout even when the image tag stays the same. Changes to anexistingSecret
do not affect the checksum, so restart both Deployments after rotating one.
The server and control plane expose /startupz, /readyz, and /livez.
Startup succeeds after NATS connects and the runtime modules start. Readiness
checks PostgreSQL and NATS; the server also ensures that its default tenant
exists. Liveness checks that the process can answer HTTP requests. The startup
probe gates the other checks, readiness marks a pod unready, and liveness can
restart its container.
Worker Jobs do not expose health endpoints. They report progress through
heartbeats instead.
Worker Jobs
For each run, the control plane creates a Kubernetes Job that starts the worker image. It passesTENANT_ID and RUN_ID to the worker. The worker loads shared
settings from a Secret and ConfigMap, then loads the run from the datastore.
Each pipeline can set its own CPU, memory, node selectors, and tolerations.
This lets Kubernetes place and size each run independently.
Common worker settings include:
controlPlane.dispatch.job.namePrefix(defaultfilament)controlPlane.dispatch.job.backoffLimit(default 1)controlPlane.dispatch.job.ttlSecondsAfterFinished(default 3600)controlPlane.dispatch.worker.restartPolicy(defaultNever)controlPlane.dispatch.worker.terminationGraceSecondscontrolPlane.dispatch.worker.activeDeadlineSeconds
Scaling
The server is stateless and can scale horizontally. Keep the control plane at one replica. Worker capacity scales through Kubernetes because each run gets its own Job and resource configuration.Vendored dependencies
The chart includes optional PostgreSQL, NATS, and Zitadel subcharts. All three are disabled by default:- Bitnami PostgreSQL with an 8Gi PVC and optional daily
pg_dumpallbackups - NATS with JetStream and a 10Gi file store
- Zitadel for authentication
auth.enabled: true,
auth.uiOrigin, and auth.zitadel.issuer to use Zitadel. An external Zitadel
instance also requires auth.zitadel.pat or an AUTH_PAT entry in
existingSecret. The vendored Zitadel setup mints its own token.
Do not use
--wait when enabling the vendored Zitadel chart. Its setup Jobs
must mint the server token before the server can become ready.