Install Dexter
Dexter runs as its own Helm release in its own namespace, configured by one values file. It does not have to share a cluster with Kloudfuse: it reads your telemetry through the Kloudfuse MCP server.
Prerequisites
-
A Kubernetes cluster with a default StorageClass, and
kubectlaccess to it. -
Helm 3.8 or later.
-
The
token.jsonthat Kloudfuse provided for your Kloudfuse install. -
An Anthropic API key, or a Claude Max OAuth token.
-
A Kloudfuse cluster with the remote MCP server enabled, and a service account token for it.
-
To serve Dexter on your own domain (step 6): cert-manager installed in the cluster, and a DNS name you can point at a load balancer.
1. Log in to the Helm registry
cat token.json | helm registry login -u _json_key --password-stdin us-east1-docker.pkg.dev
2. Create the namespace and image pull secret
The chart uses this secret by default, the same one a Kloudfuse install creates.
kubectl create namespace dexter
kubectl create secret docker-registry kfuse-image-pull-credentials \
--namespace dexter --docker-server us.gcr.io --docker-username _json_key \
--docker-password="$(cat token.json)"
3. Create the values file
Save this as dexter-values.yaml. As it stands, it installs Dexter privately; steps 5 and 6 uncomment its two sections.
# Values for the Dexter Helm chart: the whole install in one file.
#
# helm install dexter oci://us-east1-docker.pkg.dev/mvp-demo-301906/kfuse-helm/dexter \
# --version <VERSION> --namespace dexter -f dexter-values.yaml
#
# To change something later, edit this file and run the same command with `helm upgrade`.
#
# As it stands, this installs Dexter privately. Reach it with
# kubectl -n dexter port-forward svc/dexter 3000:3000
# The image pull secret defaults to kfuse-image-pull-credentials, the one a Kloudfuse install creates.
# --- Sign-in ---------------------------------------------------------------------------------------
# Required before Dexter is reachable from a network: the chart refuses a public host without it.
# The dexter-auth Secret holds SESSION_SECRET, plus DEXTER_LOCAL_USERS for local accounts.
#
# env:
# DEXTER_AUTH_REQUIRED: "1"
# DEXTER_ADMIN_EMAILS: "admin@example.com"
# envFromSecrets:
# - dexter-auth
# --- Public access ---------------------------------------------------------------------------------
# Serves Dexter at https://<host> through its own load balancer, with a Let's Encrypt certificate.
# Needs cert-manager in the cluster, and a DNS record that points the host at the load balancer.
#
# ingress:
# enabled: true
# host: dexter.example.com
#
# The cloud assigns the load balancer's address and it changes if the Service is recreated. To keep
# one address across reinstalls, reserve a REGIONAL static IP in the cluster's region — a GCE
# Ingress's GLOBAL address cannot be used by a LoadBalancer Service.
#
# ingress-nginx:
# controller:
# service:
# loadBalancerIP: 34.1.2.3
#
# Already running an ingress controller? Serve the Ingress from it instead of creating a second
# load balancer:
#
# ingress-nginx:
# enabled: false
# ingress:
# enabled: true
# host: dexter.example.com
# className: <the existing IngressClass>
4. Install Dexter
helm install dexter oci://us-east1-docker.pkg.dev/mvp-demo-301906/kfuse-helm/dexter \
--namespace dexter \
--version <VERSION> \ (1)
-f dexter-values.yaml
kubectl -n dexter rollout status deployment/dexter
| 1 | Replace <VERSION> with the Dexter chart version from your Kloudfuse contact. |
This installs one Deployment, a Service, and a persistent volume for Dexter’s data, with no load balancer. Every later change is an edit to dexter-values.yaml, applied with the same command using helm upgrade in place of helm install.
5. Turn on sign-in
Until now, anyone who can reach Dexter is an admin. Create an admin account and require sign-in before you expose Dexter.
-
Choose a password for the admin account and hash it with the Bun runtime inside the Dexter pod. The command prompts for the password and passes it on standard input, which keeps it out of your shell history and process list:
printf 'Admin password: '; read -rs ADMIN_PASSWORD; echo ADMIN_HASH=$(printf '%s' "$ADMIN_PASSWORD" | kubectl -n dexter exec -i deployment/dexter -- \ bun -e 'console.log(await Bun.password.hash(await Bun.stdin.text()))') unset ADMIN_PASSWORD -
Create a secret that holds a session key and the admin account. Replace
<ADMIN_EMAIL>with the admin’s email address:ADMIN_USER=$(printf '[{"id":"admin","email":"%s","name":"Admin","passwordHash":"%s"}]' '<ADMIN_EMAIL>' "$ADMIN_HASH") kubectl -n dexter create secret generic dexter-auth \ --from-literal=SESSION_SECRET="$(openssl rand -hex 32)" \ --from-literal=DEXTER_LOCAL_USERS="$ADMIN_USER" -
In
dexter-values.yaml, uncomment the Sign-in section and set the admin email:env: DEXTER_AUTH_REQUIRED: "1" DEXTER_ADMIN_EMAILS: "<ADMIN_EMAIL>" envFromSecrets: - dexter-authyaml -
Apply the change:
helm upgrade dexter oci://us-east1-docker.pkg.dev/mvp-demo-301906/kfuse-helm/dexter \ --namespace dexter \ --version <VERSION> \ -f dexter-values.yaml -
Wait for Dexter to restart, open it through a port-forward, and sign in at
http://localhost:3000with<ADMIN_EMAIL>and the password you chose:kubectl -n dexter rollout status deployment/dexter kubectl -n dexter port-forward svc/dexter 3000:3000
To sign in through your identity provider (Okta, Google, or Azure AD) instead of a local account, open Dexter through the port-forward before you turn on sign-in, add the provider under Admin > Identity providers, and create the secret with SESSION_SECRET only.
|
6. Serve Dexter on your domain
Skip this step to keep Dexter private and reach it through a port-forward.
-
In
dexter-values.yaml, uncomment the Public access section and sethostto the DNS name for Dexter:ingress: enabled: true host: <HOST>yaml -
Apply the change with the same
helm upgradecommand as in step 5. Dexter gets its own load balancer, HTTPS with a Let’s Encrypt certificate, and signs users in onhttps://<HOST>;. -
Find the load balancer’s
EXTERNAL-IP:kubectl -n dexter get svc -l app.kubernetes.io/instance=dexter,app.kubernetes.io/component=controller -
Create a DNS
Arecord that points<HOST>at that address. cert-manager issues the certificate a minute or two after the name resolves. Check it with the following command. AfterREADYshowsTrue, allow a few seconds before HTTPS serves the certificate; until then, Dexter’s ingress controller presents a self-signed placeholder:kubectl -n dexter get certificate
The chart adds the load balancer only after sign-in is required (step 5), and stops with a message if cert-manager is not installed. If the cluster already runs an ingress controller, use it instead: add ingress-nginx.enabled: false to the values file and set ingress.className to that controller’s IngressClass.
|
The cloud assigns the load balancer’s address, and it changes if the load balancer is ever recreated. To keep one address for good, reserve a regional static IP in the cluster’s region before this step and set it in dexter-values.yaml as ingress-nginx.controller.service.loadBalancerIP (the values file shows where). The load balancer takes that address, so the DNS record never has to change. A global address, the kind a GCE Ingress uses, cannot be assigned to it.
|
7. Connect Anthropic and Kloudfuse
-
Open Dexter at
https://<HOST>;, or athttp://localhost:3000through the port-forward if you skipped step 6, and sign in. -
Under Settings > Connections, connect:
-
Anthropic: your Anthropic API key or Claude Max OAuth token.
-
Kloudfuse: the MCP address of your Kloudfuse cluster,
https://<KLOUDFUSE_HOST>/mcp, and its service account token.
-
Dexter stores both on its persistent volume, so they survive restarts and upgrades.
Verify
curl https://<HOST>/readyz
The command returns {"status":"ok"}. If you skipped step 6, run it against http://localhost:3000/readyz while the port-forward is open. Then create an incident to confirm that Dexter can read your telemetry.