Self-hosted on Kubernetes / OpenShift
Deploy the Sluicio cell with the Helm chart — install from the OCI registry or a checkout, pick a values variant, activate Enterprise with a license Secret, expose it via Ingress or Routes, and harden with NetworkPolicies and PodDisruptionBudgets.
The single-host bootstrap is the right shape for most installs. If your organization standardizes on Kubernetes or OpenShift, the cell Helm chart (deploy/helm/cell in the app repo, Apache-2.0 licensed) is the supported path instead — this guide walks an Enterprise install end to end.
One chart serves both editions. Enterprise is activated by the license key at runtime; the same chart without a license runs the Community Edition, which is a fully valid deployment — nothing below except the license step is Enterprise-specific.
The chart is linted, templated and kubeconform-validated in CI across all three values variants, and smoke-tested end to end in a kind cluster.
Get the chart
Section titled “Get the chart”For releases after v0.11.40, install straight from the OCI registry — the chart version matches the release without the v, and its appVersion pins the matching images:
helm install cell oci://ghcr.io/sluicio/charts/sluicio-cell --version <X.Y.Z>Up to and including v0.11.40, install from a repo checkout instead:
git clone https://github.com/SLUICIO/sluicio-app.gitcd sluicio-apphelm install cell ./deploy/helm/cell -f deploy/helm/cell/values-external-db.yamlImages are public on ghcr.io/sluicio, so no pull secrets are needed unless you mirror them into a private registry (then set global.imagePullSecrets).
Pick a values variant
Section titled “Pick a values variant”The chart ships three starting points — copy one and edit it rather than assembling values from scratch:
| Variant | What it does | Use it for |
|---|---|---|
values-bundled.yaml | Runs single-replica Postgres + ClickHouse in-cluster with PVCs (non-HA) | Evaluation and small installs |
values-external-db.yaml | Bring your own databases — Postgres DSN (postgres.dsn) and ClickHouse endpoint/credentials (clickhouse.*) | Production (recommended) |
values-openshift.yaml | Passes the restricted-v2 SCC clean — no fixed UIDs or fsGroup — and pairs with Routes | OpenShift |
cell-api applies its Postgres migrations and creates the ClickHouse tables on startup, so external databases only need to exist and be reachable with the credentials you provide.
Activate Enterprise with a license Secret
Section titled “Activate Enterprise with a license Secret”Create a Secret holding the license key, then reference it from the chart. The key inside the Secret defaults to license:
kubectl create secret generic sluicio-license --from-literal=license=<key>helm upgrade cell oci://ghcr.io/sluicio/charts/sluicio-cell --version <X.Y.Z> \ --reuse-values --set license.existingSecret=sluicio-licensePrefer license.existingSecret over the inline license.key value — with a referenced Secret the key never lands in values files, Helm release history, or CI logs. Unlicensed, the install keeps running as Community Edition; the license flips on Enterprise features at runtime, no reinstall needed.
Running the Community Edition
Section titled “Running the Community Edition”There is no edition flag to set — Community Edition is simply the absence of a license. Leave both license.existingSecret and license.key empty and the chart doesn’t render the license variable at all. The same applies to the MFA key, which is independent of licensing:
helm upgrade cell oci://ghcr.io/sluicio/charts/sluicio-cell --version <X.Y.Z> \ --reuse-values \ --set license.existingSecret= --set license.key= \ --set mfa.existingSecret= --set mfa.key=Everything works except SSO, the audit log, notification profiles, retention beyond 14 days, the require-MFA policy and advanced RBAC. Adding a license later is a helm upgrade, never a reinstall — your databases are untouched.
Required configuration
Section titled “Required configuration”Two things every install should set beyond the database connection:
- MFA at-rest key — encrypts enrolled MFA secrets. Generate one with
openssl rand -base64 32and provide it viamfa.existingSecret(ormfa.keyfor a quick eval). - SMTP — invitations, alert emails and password resets need an outbound mail relay:
smtp.host,smtp.from, with credentials via the secret-backedsmtp.existingSecret.
Networking
Section titled “Networking”The UI and API must share one hostname (session cookies are scoped to it) — the standard Ingress template serves / and /api from one host, with a separate host for the OTLP ingest endpoint so producers stay pointed at ingest even if the UI moves:
ingress: enabled: true className: nginx host: sluicio.acme.com ingest: enabled: true host: ingest.acme.com
app: appUrl: https://sluicio.acme.com ingestUrl: https://ingest.acme.comTLS follows your cluster’s usual pattern (ingress.tls / ingress.ingest.tls).
On OpenShift, set route.enabled to get Routes instead of Ingress resources — the intended pairing with values-openshift.yaml.
Topology: what scales and what doesn’t
Section titled “Topology: what scales and what doesn’t”cell-api runs single-replica by design — it hosts in-process schedulers, and database migrations run at its startup. The chart pins cellApi.replicaCount to 1 with a Recreate deployment strategy; don’t scale it. A consequence worth knowing: upgrades briefly take the API down while the pod is replaced. The frontend and cell-ingest are separate deployments, so telemetry ingest keeps flowing through an API upgrade — and both can scale horizontally when load calls for it.
Optional hardening
Section titled “Optional hardening”Two opt-in switches, both off by default:
networkPolicy.enabled— default-deny ingress around the bundled data stores plus scoped ingress rules for the app pods. Only effective on a CNI that enforces NetworkPolicies (Calico, Cilium, OVN-Kubernetes…); on one that doesn’t, the objects are created but ignored.podDisruptionBudget.enabled— PodDisruptionBudgets for the frontend and ingest, meaningful once you scale them beyond 1 replica so node drains can’t take all copies down at once.
Troubleshooting
Section titled “Troubleshooting””Couldn’t reach the cell-api” / 502 Bad Gateway
Section titled “”Couldn’t reach the cell-api” / 502 Bad Gateway”The frontend proxies /api to the cell-api Service, so a 502 means nothing healthy is behind that Service — almost always cell-api not being Ready rather than a proxy misconfiguration. cell-api only reports Ready once it has connected to both Postgres and ClickHouse:
kubectl get pods -l app.kubernetes.io/instance=<release>kubectl logs deploy/<release>-cell-apicell-api stuck at CreateContainerConfigError
Section titled “cell-api stuck at CreateContainerConfigError”The kubelet couldn’t assemble the container’s configuration. In practice this means a referenced Secret is missing, or the key inside it isn’t the one the chart asks for. The pod events name the exact cause:
kubectl describe pod -l app.kubernetes.io/component=cell-api| Event message | Cause | Fix |
|---|---|---|
secret "X" not found | The Secret isn’t in the namespace you installed into | Create it there, or correct *.existingSecret |
couldn't find key Y in Secret X | The Secret exists but uses a different key name | Recreate it, or set license.secretKey / mfa.secretKey / smtp.secretKey |
The expected key names are license, mfa-key and password. Creating a Secret in one OpenShift project and installing the chart into another is the most common way to hit the first row.
A useful signal: cell-ingest has no Secret references, so ingest running while cell-api doesn’t points at this problem rather than at images, SCC or scheduling. The fastest way back to a working install is to drop the references — see Running the Community Edition.
See also: the capacity planner for sizing the databases, Deploy to production for the single-host path and database background, and the security model for ingest keys, tokens and TLS. The chart’s values.yaml in the app repo documents the full set of options.