Kubernetes (Helm)
Deploy Litefuse on Kubernetes with the official Helm chart from litefuse/litefuse-k8s. This is the recommended way to run Litefuse in production when your team operates Kubernetes.
The chart deploys the Litefuse web and worker applications together with all backing stores. Every store ships bundled by default, so a single helm install yields a working stack; each store can be pointed at an external or managed service independently.
| Component | Bundled default | External option |
|---|---|---|
| Apache Doris (analytics) | DorisCluster CR managed by the bundled Doris Operator | doris.deploy=false + doris.host |
| PostgreSQL (transactional) | groundhog2k/postgres sub-chart | postgresql.deploy=false + postgresql.host |
| Redis (cache / queues) | Valkey sub-chart | redis.deploy=false + redis.host (standalone / cluster / sentinel) |
| S3 (blob storage) | SeaweedFS all-in-one sub-chart | s3.deploy=false + s3.endpoint / AWS / Azure / GCS |
Prerequisites
- Kubernetes 1.24+
- Helm 3.18+
- A default StorageClass — Doris FE/BE, PostgreSQL, Valkey, and SeaweedFS all request PVCs by default (or set the per-store
storageClassfields) - Cluster capacity for the default single-replica footprint: roughly 6.5 CPU / 13Gi of requests and ~300Gi of volumes. For a laptop or small dev cluster, start from
examples/values-dev.yaml, which roughly halves this.
Quick Start
Install from the OCI registry (recommended)
The published package bundles all sub-chart dependencies — no helm repo add needed:
helm install litefuse oci://ghcr.io/litefuse/litefuse --version 1.0.0 \
-n litefuse --create-namespaceDiscover the configuration without cloning the repository:
helm show values oci://ghcr.io/litefuse/litefuse --version 1.0.0 # all options, annotated
helm show readme oci://ghcr.io/litefuse/litefuse --version 1.0.0 # full referenceInstall from source
git clone https://github.com/litefuse/litefuse-k8s.git && cd litefuse-k8s
helm dependency update charts/litefuse
helm install litefuse charts/litefuse -n litefuse --create-namespaceFor a development-sized install:
helm install litefuse charts/litefuse -n litefuse --create-namespace \
-f examples/values-dev.yamlWhat to expect on a fresh install
The first install brings in the Doris Operator CRDs, then creates a DorisCluster custom resource. Doris FE/BE take a few minutes to form a cluster, and the web/worker pods restart until the schema migrations succeed — this is expected. Watch progress with:
kubectl get doriscluster -n litefuse
kubectl get pods -n litefuse -wThe install is done when the DorisCluster reports FE/BE available and the web/worker pods are Running and Ready.
Access the UI
Without an ingress:
kubectl port-forward -n litefuse svc/litefuse-web 3000:3000Open http://localhost:3000 and sign up for the first account. For a real deployment, enable the ingress and set litefuse.nextauth.url to the canonical external URL. After creating your accounts, disable public sign-up with litefuse.features.signUpDisabled=true.
Configuration
All options live in values.yaml with inline documentation; the chart renders them into environment variables on the web/worker pods. Three rules:
- Prefer the structured fields (
litefuse.*,postgresql.*,redis.*,doris.*,s3.*). They are validated at render time and wired into the right Secrets automatically. litefuse.additionalEnvis the escape hatch for anything without a structured field. Setting the same variable both ways is rejected at render time.- Litefuse environment variables use the
LITEFUSE_prefix. A staleLANGFUSE_-prefixed variable is silently ignored — mind this when migrating values from langfuse-k8s.
Every sensitive field accepts either an inline value or a reference to an existing Kubernetes Secret:
someSecretField:
value: "" # inline (fine for testing)
secretKeyRef: # preferred: reference your own Secret
name: my-secret
key: my-keyCanonical URL
Required for any real deployment:
litefuse:
nextauth:
url: https://litefuse.example.comSecurity keys
| Key | Env var | Format |
|---|---|---|
litefuse.salt | SALT | any string (openssl rand -base64 32) |
litefuse.encryptionKey | ENCRYPTION_KEY | 256-bit hex (openssl rand -hex 32) |
litefuse.nextauth.secret | NEXTAUTH_SECRET | any string (openssl rand -base64 32) |
Left empty, all three are auto-generated on first install and persisted in the <release>-app Secret, which is kept across uninstalls. Losing SALT or ENCRYPTION_KEY is unrecoverable — API keys and encrypted data become unreadable.
Pin them for production, especially under GitOps where helm template cannot look up the generated Secret:
litefuse:
salt:
secretKeyRef: { name: litefuse-app-credentials, key: salt }
encryptionKey:
secretKeyRef: { name: litefuse-app-credentials, key: encryption-key }
nextauth:
secret:
secretKeyRef: { name: litefuse-app-credentials, key: nextauth-secret }Ingress
Only the web Service is exposed; the worker has no HTTP endpoint.
litefuse:
ingress:
enabled: true
className: nginx
annotations:
# SDK batch ingestion posts can be large — do not cap at the nginx 1m default
nginx.ingress.kubernetes.io/proxy-body-size: 100m
hosts:
- host: litefuse.example.com
paths:
- path: /
pathType: Prefix
tls:
enabled: true
secretName: litefuse-tlsSSO and SMTP
SSO providers (auth0, cognito, azureAd, github, gitlab, google, keycloak, okta, workos, and more) are configured under litefuse.auth.providers, and transactional email under litefuse.smtp. See the chart reference for details.
Connecting External Stores
Each bundled store follows the same pattern: <store>.deploy: false plus connection and auth fields. Validation fails at render time if a required endpoint is missing.
External Doris
doris:
deploy: false
operator:
enabled: false
host: my-doris-fe.example.com # FE endpoint (MySQL protocol + HTTP)
httpPort: 8030
queryPort: 9030
database: litefuse
auth:
username: admin
existingSecret: my-doris-credentials
existingSecretKey: password
replicationNum: 3 # keep 3 with >= 3 BEsA single-BE external Doris needs replicationNum: 1 — the default of 3 makes every CREATE TABLE fail when fewer backends are alive.
External PostgreSQL
postgresql:
deploy: false
host: my-postgres.example.com
port: 5432
auth:
username: litefuse
database: litefuse
existingSecret: my-postgres-credentials
secretKeys:
userPasswordKey: passwordFor managed/cloud Postgres, also see postgresql.directUrl (separate connection string for migrations), and postgresql.shadowDatabaseUrl (required when the database user lacks CREATE DATABASE permission).
External Redis
redis:
deploy: false
host: my-redis.example.com
port: 6379
auth:
username: "default"
existingSecret: my-redis-credentials
existingSecretPasswordKey: passwordRedis Cluster (redis.cluster.enabled + nodes) and Sentinel (redis.sentinel.*) are also supported. Configure maxmemory-policy noeviction on any external Redis/Valkey — Litefuse loses job data under eviction.
External S3 / blob storage
s3:
deploy: false
bucket: my-litefuse-bucket
region: eu-west-1
forcePathStyle: false
accessKeyId:
secretKeyRef: { name: my-s3-credentials, key: access-key-id }
secretAccessKey:
secretKeyRef: { name: my-s3-credentials, key: secret-access-key }Leave accessKeyId/secretAccessKey empty to use the pod’s ambient identity (IRSA / instance profile). For MinIO or another S3-compatible gateway, additionally set s3.endpoint and change forcePathStyle to true (the AWS example above uses false). Azure Blob and GCS are supported via s3.storageProvider.
Example Values Files
Ready-to-use values files live under examples/:
| File | Purpose |
|---|---|
values-dev.yaml | Laptop / small dev cluster: single replicas, reduced resources and volumes |
values-production.yaml | HA Doris (3 FE / 3 BE, replication 3), scaled web+worker, ingress + TLS, pinned secrets |
values-external-doris.yaml | Connect to a managed / existing Doris cluster |
minimal-installation/ | Full bundled stack with every credential sourced from one pre-created Secret (GitOps-friendly) |
Scaling
-
Each web/worker replica is one Node.js process (~1 core at saturation) — scale out, not up:
litefuse: web: replicas: 6 worker: replicas: 12 -
HPA, KEDA, and VPA blocks exist for both web and worker (
litefuse.web.hpa.*,litefuse.worker.keda.*, …). -
PodDisruptionBudgets are created by default (
maxUnavailable: 1). -
For production Doris HA, use 3 FE / 3+ BE replicas with
doris.replicationNum: 3— seeexamples/values-production.yaml. -
The Doris Operator installs cluster-scoped resources — run only one operator per Kubernetes cluster. For a second Litefuse release, set
doris.operator.enabled=falseand share the existing operator. -
Keep the whole stack on UTC (
litefuse.timezone, the default) — Doris date partitioning depends on it.
Upgrading
helm upgrade litefuse oci://ghcr.io/litefuse/litefuse --version <ver> -n litefuse- The web/worker images default to the chart’s
appVersion; pinlitefuse.image.tagto control the app version independently. The web pod runs Postgres/Doris migrations on startup. - Helm never upgrades CRDs. When a chart upgrade bumps the Doris Operator dependency, apply its updated CRDs manually (
kubectl apply -ffrom the operator release) before upgrading.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
| web/worker CrashLoopBackOff in the first minutes | Expected while Doris FE/BE form a cluster and migrations retry. Watch kubectl get doriscluster; investigate only if it persists after Doris is Ready |
helm template fails: Doris Operator CRD not found | Rendering offline or against a fresh cluster. Pass --api-versions doris.selectdb.com/v1/DorisCluster or set doris.crdCheck=false |
| Doris FE pod OOMKilled | doris.cluster.fe.jvmHeapMb too close to the container memory limit — keep ~2Gi+ headroom |
CREATE TABLE fails with replication errors | doris.replicationNum exceeds alive BEs. Single-BE clusters need replicationNum: 1 |
Worker exits: missing LITEFUSE_S3_EVENT_UPLOAD_BUCKET | A stale LANGFUSE_-prefixed env var from a langfuse-k8s migration — Litefuse only reads the LITEFUSE_ prefix |
| Jobs disappear under memory pressure (external Redis) | The external Redis/Valkey must run maxmemory-policy noeviction |
See the chart README for the full list.
Uninstalling
helm uninstall litefuse -n litefuseKept intentionally after uninstall:
- PVCs for Doris FE/BE, PostgreSQL, Valkey, and SeaweedFS (the data)
- The
<release>-appSecret (SALT/ENCRYPTION_KEY/NEXTAUTH_SECRET) and generated store-credential Secrets — they unlock those volumes
A reinstall with the same release name picks all of this up and comes back with the data intact. Delete the PVCs and Secrets manually only if you also mean to discard the data.