Skip to content

Kubernetes Operator

The KSail operator brings declarative cluster management into Kubernetes. It reconciles Cluster custom resources (ksail.io/v1alpha1), so you can provision and manage KSail-supported distributions with kubectl apply — or let your GitOps engine do it for you. An optional web UI and OIDC-authenticated REST API are included.

ComponentDescriptionToggle
OperatorController that reconciles Cluster custom resourcesoperator.enabled (default true)
Cluster CRDInstalled automatically from the chart's crds/ directory
RBACServiceAccount plus the (Cluster)Role and binding the operator needsserviceAccount.create
REST APIServed by the operator, consumed by the UIapi.bindPort (0 disables)
Web UIDashboard that talks to the REST APIui.enabled (default false)
OIDC authApp-driven login protecting the REST API and UIauth.oidc.enabled (default false)

Requires Kubernetes 1.27+ and Helm 3.8+.

  1. Install the chart. Each KSail release publishes it as an OCI artifact to GHCR — pin a release version:

    Terminal window
    helm install ksail-operator oci://ghcr.io/devantler-tech/charts/ksail-operator \
    --version <version> --namespace ksail-system --create-namespace
  2. Apply a Cluster resource. The operator picks it up and provisions the cluster:

    apiVersion: ksail.io/v1alpha1
    kind: Cluster
    metadata:
    name: my-cluster
    namespace: ksail-system
    spec:
    cluster:
    distribution: VCluster
  3. Watch it reconcile:

    Terminal window
    kubectl get clusters -n ksail-system -w

Distributions that run nested inside the host cluster (VCluster, K3s) work out of the box. Docker-based distributions (Vanilla/Kind, K3d) need the host Docker socket mounted via operator.dockerSocket.enabled=true — this is privileged and single-node, so prefer nested distributions in-cluster. See the Kubernetes (Nested) provider for how nested clusters run as pods.

Terminal window
helm upgrade --install ksail-operator oci://ghcr.io/devantler-tech/charts/ksail-operator \
--version <version> --namespace ksail-system --create-namespace \
--set ui.enabled=true

Without an Ingress, port-forward to reach it (the Service is named <release-name>-ksail-operator-ui):

Terminal window
kubectl port-forward -n ksail-system svc/ksail-operator-ksail-operator-ui 8080:80

Set ui.readOnly=true in GitOps-enforced environments so the Git repository stays the single source of truth — the operator enforces read-only mode server-side, not just in the frontend.

OIDC closes the otherwise-unauthenticated REST API. The API owns the login/callback flow as a confidential client, so the client secret stays server-side. The provider must reach the API's callback at a stable URL — typically through an Ingress:

Terminal window
helm upgrade --install ksail-operator oci://ghcr.io/devantler-tech/charts/ksail-operator \
--version <version> --namespace ksail-system --create-namespace \
--set ui.enabled=true \
--set ui.ingress.enabled=true \
--set ui.ingress.hosts[0].host=ksail.example.com \
--set auth.oidc.enabled=true \
--set auth.oidc.issuerURL=https://dex.example.com \
--set auth.oidc.clientID=ksail \
--set-string auth.oidc.clientSecret=CLIENT_SECRET \
--set auth.oidc.redirectURL=https://ksail.example.com/api/v1/auth/callback

Register the redirect URL with your provider. To keep secrets out of --set and values files, pre-create a Secret with keys client-secret and session-secret and reference it via auth.oidc.existingSecret.

Terminal window
helm uninstall ksail-operator --namespace ksail-system

Helm does not remove CRDs installed from crds/. Delete the Cluster CRD manually if you no longer need it — this also deletes all Cluster resources:

Terminal window
kubectl delete crd clusters.ksail.io

The full values reference — images, replicas, leader election, resources, Ingress, and OIDC — lives in the chart README.