Skip to content
GitHub

Production install

Item Requirement Notes
Kubernetes ≥ 1.29 k3s, kind, EKS, GKE or AKS
StorageClass with ReadWriteOnce required with SQLite users, sessions, releases and the audit log live on a 1 GiB PVC; 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; plain flannel does not

kuben doctor checks all of the above from inside the pod or from a workstation with a kubeconfig.

Terminal window
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.gateway=kuben-system/kuben \
--set platform.clusterIssuer=letsencrypt

The 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 SQLite on a PVC PostgreSQL. Required for replicaCount > 1 (the chart fails without it); switches to rolling updates and drops the PVC
persistence.size 1Gi the PVC carries helm.sh/resource-policy: keep and survives helm uninstall
security.cookieSecure true __Host- cookie with Secure. Only set to false 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.

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 RuntimeDefault seccomp profile
  • with the Recreate strategy on SQLite (its volume is ReadWriteOnce) and rolling updates on PostgreSQL
  • 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.

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:

Terminal window
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-system

Whichever you choose, the console must be served over HTTPS: the session cookie is Secure.

  1. Read the generated password:

    Terminal window
    kubectl -n kuben-system get secret kuben-initial-admin -o jsonpath='{.data.password}' | base64 -d; echo
  2. Open the console (publicUrl, or a port-forward while the route is not ready), sign in as admin.email and change the password under Account.

  3. Delete the bootstrap Secret:

    Terminal window
    kubectl -n kuben-system delete secret kuben-initial-admin
  4. Invite your team from Team; see Teams and roles.

If the admin password is ever lost:

Terminal window
kubectl -n kuben-system exec deploy/kuben -- /kuben reset-admin