Self-host with the Helm chart
The Fleans release pipeline publishes a packaged Helm chart (fleans-<VER>.tgz)
on every v<SemVer> tag. This guide walks through the install lifecycle
against a real Kubernetes cluster: acquire the tarball, install with sane
defaults, harden for production, upgrade across releases, and recover from
common failures. For chart internals (component matrix, kind smoke test,
chart structure), the canonical reference is
Self-Hosting on Kubernetes.
Prerequisites
Section titled “Prerequisites”- Kubernetes 1.27+ (the chart is built and tested against the current three minor versions).
- Helm 3.12+. Older 3.x may work but is unsupported.
- A
StorageClassif you keep the chart-managed Postgres StatefulSet (postgres.persistentVolume.enabled=true, the default). Skip when pointing at an external Postgres. - Pull access to
ghcr.io/nightbaker/fleans-{api,web,mcp}— public for the Fleans repo’s published images. ProvideimagePullSecretsif you mirror to a private registry. - A namespace you control (
kubectl create ns fleansor use any existing).
1. Download the chart
Section titled “1. Download the chart”gh release download v0.1.0-beta --repo nightBaker/fleans -p 'fleans-*.tgz'Or via curl:
curl -LO https://github.com/nightBaker/fleans/releases/download/v0.1.0-beta/fleans-0.1.0-beta.tgzVerify the chart and images
Section titled “Verify the chart and images”The release pipeline signs both the chart tarball (as a blob) and every container image (by manifest digest). Run two checks before helm install:
1. Verify the helm chart tarball. Download fleans-0.1.0-beta.tgz, fleans-0.1.0-beta.tgz.sig, and fleans-0.1.0-beta.tgz.crt from the same GitHub Release, then:
cosign verify-blob \ --certificate fleans-0.1.0-beta.tgz.crt \ --signature fleans-0.1.0-beta.tgz.sig \ --certificate-identity-regexp "https://github.com/nightBaker/fleans/.github/workflows/release.yml@refs/tags/v.*" \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ fleans-0.1.0-beta.tgz2. Verify each container image. The chart pulls four images (one of which — fleans-api — is reused by the core and worker Deployments per the chart’s values.yaml design; even though the Helm chart pulls only image.api for both core and worker Deployments at runtime, the release pipeline publishes all four as distinct signed images for users who want a Worker silo deployable in non-chart deployments):
for SVC in api web worker mcp; do cosign verify \ --certificate-identity-regexp "https://github.com/nightBaker/fleans/.github/workflows/release.yml@refs/tags/v.*" \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ ghcr.io/nightbaker/fleans-$SVC:0.1.0-betadoneFor production Kubernetes installs, the recommended enforcement is the Sigstore Policy Controller (policy.sigstore.dev/v1beta1 ClusterImagePolicy) or Kyverno’s verifyImages/verifyManifests rules.
2. Quick install
Section titled “2. Quick install”helm install fleans ./fleans-0.1.0-beta.tgz \ --namespace fleans \ --create-namespace
kubectl wait --for=condition=ready pod \ -l app.kubernetes.io/instance=fleans \ --timeout=180s --namespace fleans
kubectl port-forward -n fleans svc/fleans-web 8080:8080Open http://localhost:8080 — the admin UI loads.
Tear down at any time with helm uninstall fleans -n fleans.
3. values.yaml reference
Section titled “3. values.yaml reference”The defaults below are extracted from charts/fleans/values.yaml. Override
on the install command line via --set or pass a -f my-values.yaml overlay.
| Key | Default | Description |
|---|---|---|
image.api.repository | ghcr.io/nightbaker/fleans-api | Image used by both core and worker Deployments. |
image.web.repository | ghcr.io/nightbaker/fleans-web | Blazor Server admin UI image. |
image.mcp.repository | ghcr.io/nightbaker/fleans-mcp | MCP server image. |
image.tag | (empty — falls back to chart appVersion) | Pin to a specific tag for reproducible installs. |
image.pullPolicy | IfNotPresent | Standard Kubernetes pull policy. |
imagePullSecrets | [] | Add [{name: my-pull-secret}] when mirroring images. |
core.replicas | 1 | Number of Core silos. |
core.resources.requests | cpu: 250m, memory: 512Mi | Right-sized for ~10 active workflows; bump for higher throughput. |
core.resources.limits.memory | 1Gi | Hard cap. |
worker.enabled | false | Set true to dedicate pods to [StatelessWorker] script/condition grains. |
worker.replicas | 1 | Worker silo count when worker.enabled=true. |
worker.nodeSelector / worker.tolerations | {} / [] | Pin worker silos to spot/cheaper nodes. |
customWorker.enabled | false | Set true to host user-written custom-task plugins on a dedicated silo built from the fleans-custom-worker-example template. |
customWorker.replicas | 1 | Custom-worker silo count when customWorker.enabled=true. |
web.enabled | true | Disable to ship a headless cluster (no admin UI). |
web.replicas | 1 | Blazor Server is sticky-session-friendly; HA needs careful affinity. |
web.service.port | 8080 | Service port for the UI. |
mcp.enabled | true | Disable when no MCP-aware AI agents will connect. |
mcp.service.port | 5200 | MCP server port. |
ingress.enabled | false | Toggle the chart’s Ingress for the admin UI. |
ingress.className | "" | e.g. nginx, traefik. Empty inherits the cluster default. |
ingress.host | fleans.example.com | Public hostname. |
ingress.tls.enabled | false | Set true + ingress.tls.secretName to terminate TLS. |
persistence.provider | Postgres | Postgres (production) or Sqlite (dev parity, single-replica only — see chart-side caveat). |
postgres.enabled | true | Set false to bring your own Postgres (see §4). |
postgres.image.tag | "16" | Stays in sync with the test matrix in Fleans.Persistence.Tests. |
postgres.database | fleans | DB name created on first boot. |
postgres.username | fleans | Workflow user. |
postgres.password | "" | Empty = chart auto-generates and stores in a Secret. |
postgres.existingSecret | "" | Reference an existing Secret with key postgres-password. |
postgres.persistentVolume.enabled | true | Disable for ephemeral data; persistence requires a StorageClass. |
postgres.persistentVolume.size | 8Gi | Size the PVC. |
redis.enabled | true | Required — Orleans clustering depends on Redis. |
redis.image.tag | "7-alpine" | Pinned. |
redis.persistentVolume.enabled | false | Off by default; Orleans state is rebuilt from Postgres event store. |
auth.authority | "" | OIDC issuer URL. Leaving empty disables auth (Fleans.Web fallback). |
auth.clientId | "" | Web admin UI OIDC client ID. |
auth.clientSecretExistingSecret | "" | Reference a Secret with key client-secret. Use this in production. |
auth.clientSecret | "" | Inline OIDC client secret. Not recommended for production. |
streaming.provider | Memory | Memory (in-process) or Kafka (durable). |
streaming.redis.totalQueueCount | 8 | Orleans pulling-agent count for Redis streaming. |
streaming.kafka.brokers | "" | Comma-separated Kafka brokers, e.g. kafka.kafka.svc:9092. |
streaming.kafka.queueCount | 8 | Orleans pulling-agent count for Kafka streaming. |
extraEnv | [] | Extra env vars on every Fleans workload (api, web, mcp). Use for ConnectionStrings__fleans overrides. |
To tune Orleans consumer parallelism (pulling-agent count per cluster) for higher throughput, set Fleans__Streaming__Redis__TotalQueueCount (Redis), Fleans__Streaming__Kafka__QueueCount (Kafka), or supply an explicit Fleans__Streaming__AzureQueue__QueueNames__0..N list — see Tuning throughput for the sizing heuristic, rehash caveat, and Kafka-side NumPartitions tuning.
Cross-link: see the chart component matrix for the per-Deployment image / port table — not duplicated here.
4. Production checklist
Section titled “4. Production checklist”Each item below maps to a values.yaml override. Combine into a single
values-prod.yaml overlay and pass with -f.
External Postgres (managed RDS / Cloud SQL / Aiven)
Section titled “External Postgres (managed RDS / Cloud SQL / Aiven)”postgres: enabled: falsepersistence: provider: PostgresextraEnv: - name: ConnectionStrings__fleans valueFrom: secretKeyRef: name: fleans-pg key: connection-stringCreate the Secret separately (out-of-band or via your secrets operator):
kubectl create secret generic fleans-pg \ -n fleans \ --from-literal=connection-string='Host=my-pg.example.com;Port=5432;Database=fleans;Username=fleans;Password=...;Ssl Mode=Require'The Postgres user needs CREATE TABLE on first boot (for migrations), then
only INSERT/UPDATE/SELECT/DELETE thereafter.
OIDC for the admin UI
Section titled “OIDC for the admin UI”auth: authority: https://idp.example.com/realms/fleans clientId: fleans-web clientSecretExistingSecret: fleans-oidc # Secret with key `client-secret`The chart wires the Web pods’ env from this Secret. See
Authentication for the OIDC scopes
the admin UI requests and the API’s JWT validation contract.
Ingress with TLS via cert-manager
Section titled “Ingress with TLS via cert-manager”ingress: enabled: true className: nginx host: fleans.example.com annotations: cert-manager.io/cluster-issuer: letsencrypt-prod tls: enabled: true secretName: fleans-tlscert-manager populates fleans-tls via the cert-manager.io/cluster-issuer
annotation; the chart references the secret in the Ingress’s tls block.
Dedicated worker silos
Section titled “Dedicated worker silos”For compute-isolation of script / condition grains:
worker: enabled: true replicas: 2 nodeSelector: workload: fleans-worker tolerations: - key: dedicated value: fleans-worker effect: NoScheduleResource requests / limits
Section titled “Resource requests / limits”The chart’s defaults assume a small workload. For production load, raise
core.replicas and bump CPU/memory based on observed throughput in the
Orleans Dashboard. See Observability for
the dashboard URL and metrics that matter.
Image-pull secrets (private registry mirroring)
Section titled “Image-pull secrets (private registry mirroring)”imagePullSecrets: - name: my-registry-pull5. Upgrade path
Section titled “5. Upgrade path”gh release download v0.2.0 --repo nightBaker/fleans -p 'fleans-*.tgz'helm upgrade fleans ./fleans-0.2.0.tgz \ --namespace fleans \ -f values-prod.yamlHelm rolls the new pods forward; Fleans.Api runs pending EF migrations on
startup against the existing Postgres state. If the rollout misbehaves:
helm rollback fleans <REVISION> -n fleanshelm history fleans -n fleans lists revision numbers. Rollback is
non-destructive to Postgres; the database schema is forward-compatible
within the documented per-release migration window.
6. Troubleshooting
Section titled “6. Troubleshooting”ImagePullBackOff. Either the registry is private andimagePullSecretsis missing, or the tag doesn’t exist.kubectl describe pod <name>shows the underlying error.CrashLoopBackOffonfleans-apiwith Postgres connection error. Whenpostgres.enabled=false, theextraEnvConnectionStrings__fleansmust resolve before the API pod starts. Check the referencedSecretviakubectl get secret fleans-pg -o jsonpath='{.data.connection-string}' | base64 -d.- OIDC
redirect_uri_mismatchfrom the IdP. Add the new ingress host (e.g.https://fleans.example.com/signin-oidc) to the IdP’s allowed redirect URIs. - Live-edit drift after
kubectl edit. Helm tracks the rendered manifest; in-cluster edits get reverted on the nexthelm upgrade. Inspect effective values withhelm get values fleans -n fleans. - HPA fights Orleans placement. Orleans grains stick to silos; an HPA
scaling Core or Worker silos in/out can churn placement. Set
core.replicas/worker.replicasexplicitly for stable workloads.
See also
Section titled “See also”- Self-Hosting on Kubernetes — chart
component matrix,
kindsmoke test, chart-internal architecture. - Configuration — full configuration
matrix (env-var →
values.yamlmapping). - Persistence — Postgres + Sqlite providers, external-Postgres connection-string contract.
- Authentication — OIDC scopes, JWT validation, the cookie + bearer flows.
- Streaming — Kafka provider configuration and production-readiness caveat.
- Cutting a Release — maintainer runbook for publishing a new chart tarball.