Skip to content
Install on Kubernetes

Install on Kubernetes

You need a cluster (kind works), kubectl, Helm 3 and Docker. Nothing here replaces what you learned on the laptop: the class is the same document, and your agent is the same code.

You need a cluster (kind works), kubectl, Helm 3 and Docker.

  1. Build the image and get it onto the cluster.

    docker build -t kslate:dev .
    kind load docker-image kslate:dev --name my-cluster      # or push to your registry
  2. Install the chart.

    helm install kslate deploy/helm/kslate -n kslate --create-namespace \
      --set image.tag=dev --set postgres.password=change-me

    The chart installs the SharedContext CRD, two gateway pods, one worker pod, a Postgres pod for development, and the Services and RBAC they need. The gateway Service is kslate-gateway in the kslate namespace. It serves HTTP/JSON and MCP at /mcp.

  3. Check it is ready.

    kubectl -n kslate get pods
    kubectl -n kslate port-forward svc/kslate-gateway-metrics 9100:9100 &
    curl -s localhost:9100/readyz

    /readyz returns 200 once the database schema is in place.

When the chart is published, this will be the install line. Nothing is at this path yet:

helm install kslate oci://ghcr.io/kslate-dev/charts/kslate -n kslate --create-namespace

Add a class

A class is a SharedContext resource. It is the same document, with the same spec, as the contexts.yaml the local path passes to --policy: one decoder and one validator read both. What changes on a cluster is that the API server holds it, metadata.namespace decides which object owns a duplicated class name, and the controller writes status.

To try the example class from the design, enable it in the chart:

helm upgrade kslate deploy/helm/kslate -n kslate --reuse-values \
  --set example.enabled=true --set example.createNamespace=true

It is off by default because it is a real policy: it lets any ServiceAccount in a namespace called kagent write to incidents. For your own class, write a SharedContext and kubectl apply it. The CRD reference has the shape. kubectl get sharedcontexts shows whether it loaded.

Settings you will want past a first run

SettingWhat it does
postgres.enabled=false with external.dsn or external.existingSecretUse your own Postgres. The bundled one is a single pod with no persistent disk. Its data is lost on restart.
tls.enabled=true, tls.secretNameServe TLS from a kubernetes.io/tls Secret. Otherwise put kslate behind a mesh or an ingress that terminates TLS.
watchNamespaceOnly watch one namespace for classes. Class names are global across the cluster, so a duplicate name in another namespace is refused.
gateway.grpcPortTurn on the gRPC transport.
serviceMonitor.enabled, networkPolicyPrometheus scraping, and who may scrape. Metric labels include class, field and role names.
gateway.replicasGateways are stateless. Add as many as you like. They share one Postgres.

Every value is in the Helm reference.

The sidecar image

For the kagent sidecar path:

docker build -f Dockerfile.reconciler -t kslate-reconciler:dev .
kind load docker-image kslate-reconciler:dev --name my-cluster

Full test on kind

make test-k8s builds the image, creates a kind cluster, installs the chart with the example class and runs the end-to-end tests. It needs kind, kubectl, helm and Docker.