Production install
Prerequisites
Section titled “Prerequisites”| Item | Requirement | Notes |
|---|---|---|
| Kubernetes | ≥ 1.29 | k3s, kind, EKS, GKE or AKS |
StorageClass with ReadWriteOnce |
required for the chart’s own PostgreSQL | users, sessions, releases and the audit log live on its 8 GiB volume; apps with volumes also use it |
| Gateway API CRDs and a Gateway controller | for public app access | Traefik v3, Envoy Gateway or Cilium |
| cert-manager | for HTTPS | run with Gateway API support: --set config.enableGatewayAPI=true |
| metrics-server | for autoscaling | the HPA does not work without it; k3s ships it |
A CNI that enforces NetworkPolicy |
for tenant isolation | Calico and Cilium do, and k3s does with its built-in policy controller; plain flannel elsewhere does not |
kuben doctor checks all of the above from inside the pod or from a workstation with a kubeconfig.
Check the cluster first
Section titled “Check the cluster first”kuben doctor --clusterIt reads your kubeconfig, changes nothing, and lists what each feature needs and what is missing (Gateway, HTTPS, volumes, isolation, autoscaling), with the permissions Kuben needs. Without a Gateway controller, Envoy Gateway is the documented choice; set platform.gatewayClassName=eg then. Kuben uses what the cluster has and never upgrades CRDs it does not own. helm install --dry-run=server validates the chart against the cluster before anything is created.
Install with Helm
Section titled “Install with Helm”helm install kuben oci://ghcr.io/teamtem-dev/charts/kuben \ --namespace kuben-system --create-namespace \ --set publicUrl=https://kuben.example.com \ --set platform.baseDomain=apps.example.com \ --set platform.gatewayClassName=traefik \ --set platform.clusterIssuer=letsencryptThe values that matter most:
| Value | Default | Purpose |
|---|---|---|
publicUrl |
empty | the URL users open; used for absolute links |
admin.email |
admin@kuben.local |
initial admin |
admin.existingSecret |
empty | Secret with a password key. Empty: a password is generated on first start into the Secret kuben-initial-admin, never logged |
database.url / database.existingSecret |
empty: the chart’s own PostgreSQL | an external PostgreSQL; the chart then runs none of its own. Use one for several replicas or high availability |
postgresql.persistence.size |
8Gi |
the volume of the chart’s own PostgreSQL. helm uninstall keeps it and the Secret with its passwords |
security.cookieSecure |
true |
__Host- cookie with Secure. auto follows publicUrl (https → Secure); false only for local development over HTTP |
platform.* |
empty | the KubenConfig singleton: baseDomain, gateway, clusterIssuer |
route.enabled |
false |
publish Kuben’s own console through an HTTPRoute on your Gateway |
The full list is in the Helm chart reference. The Gateway and the ClusterIssuer themselves are described in Exposing apps and HTTPS.
What the chart deploys
Section titled “What the chart deploys”The Kuben pod runs:
- as a non-root user (UID 65532), from a distroless image
- with a read-only root filesystem, all capabilities dropped and the
RuntimeDefaultseccomp profile - with rolling updates (
maxUnavailable: 0,maxSurge: 1), so an upgrade needs no downtime - with
KUBEN_SECURITY__TRUST_FORWARDED_FOR=true, because it sits behind the Gateway, which appends the client address - with
KUBEN_KUBE__LEADER_ELECTION=true, so several replicas never run the controllers twice
Requests default to 50m CPU and 64 Mi of memory, with a 256 Mi limit. A pod reports ready only after its informers have listed every Project, Environment, App and Pod once, so a fresh replica never answers 404 for objects that exist.
Unless database.url or database.existingSecret is set, the chart also runs PostgreSQL 17 as a single-instance StatefulSet kuben-postgresql (requests 50m CPU and 128 Mi, limit 512 Mi). Kuben connects to it as the ordinary role kuben, which owns the database kuben, so row-level security applies; the superuser postgres is for maintenance only. kuben doctor warns (database role) when Kuben connects as a superuser or a BYPASSRLS role. Details are in the Helm chart reference.
Publish the console
Section titled “Publish the console”Either put your own ingress in front of the kuben Service (port 80), or let the chart create an HTTPRoute on the same Gateway the apps use:
helm upgrade kuben oci://ghcr.io/teamtem-dev/charts/kuben -n kuben-system --reuse-values \ --set route.enabled=true \ --set route.hostname=kuben.example.com \ --set route.gateway.name=kuben --set route.gateway.namespace=kuben-systemWhichever you choose, the console must be served over HTTPS: the session cookie is Secure.
First sign-in
Section titled “First sign-in”-
Read the generated password:
Terminal window kubectl -n kuben-system get secret kuben-initial-admin -o jsonpath='{.data.password}' | base64 -d; echo -
Open the console (
publicUrl, or a port-forward while the route is not ready), sign in asadmin.emailand change the password under Account. -
Delete the bootstrap Secret:
Terminal window kubectl -n kuben-system delete secret kuben-initial-admin -
Invite your team from Team; see Teams and roles.
If the admin password is ever lost:
kubectl -n kuben-system exec deploy/kuben -- /kuben reset-admin- Exposing apps and HTTPS: the Gateway, the ClusterIssuer, wildcard certificates.
- High availability: an external PostgreSQL and several replicas.
- Backup and restore and Upgrading.