KBkilterKB
userdev

Namespaces & Isolation

Kilter's core promise is that projects can't interfere with each other. Four layers deliver it, and understanding them explains most "why is my connection string like that?" questions.

The four layers

1. Cluster. Each project gets its own KIND cluster, kilter-<project>. Two projects never share an API server, a node, or a scheduler — it's separation at the level of "different machines".

2. Namespace. Inside its cluster, a project's workloads live in <project>-dev (e.g. kilterkb-dev). The namespace scopes names — every project can have a Service called postgres — and appears in every in-cluster DNS name.

3. Kubeconfig. Kilter never touches ~/.kube/config. Each project's credentials live at ~/.cache/kilter/<name>/kubeconfig, containing exactly one context for that project's cluster. There is no context switching and no way for a stray kubectl delete to land on the wrong cluster.

4. Ports. Each project gets deterministic, non-overlapping localhost port allocations, so two projects' postgres instances can run simultaneously. Details in Ports.

Two addresses for everything

Every service has two addresses, and kilter env prints both:

# In-cluster (K8s DNS):
DATABASE_URL=postgresql://…@postgres.kilterkb-dev.svc:5432/…
# Localhost (NodePort mapping):
DATABASE_URL=postgresql://localhost:30530/…

The in-cluster form is <service>.<namespace>.svc:<container-port> — Kubernetes DNS, resolvable only by pods inside the cluster. Your app container uses these: it talks to postgres.kilterkb-dev.svc:5432 over the cluster network.

The localhost form is for everything running on your host: your browser, psql, a GUI database client, curl. Same service, reached through the port mapping instead of cluster DNS.

Use the right address for where the code runs

Code running in a pod cannot reach localhost:30530 (that's the pod's own loopback), and your host cannot resolve postgres.kilterkb-dev.svc. Mixing them up produces connection-refused errors that look like the service is down when it's fine.

Why .env files go stale

Isolation is generated: namespaces, DNS names, and ports all derive from the project name and kilter's allocations. A .env file is a snapshot of those values at one moment. It goes stale when:

  • ports differ on another machine or after a cluster recreate,
  • a copied .env carries another project's ports (each project's allocations differ by design),
  • a service was added, removed, or renamed since the snapshot.

The fix is a habit, not a file: kilter env is the source of truth. When a connection string misbehaves, diff your .env against kilter env before debugging anything else.

Seeing the layers

kilter ps                                          # all running kilter projects
KUBECONFIG=~/.cache/kilter/<name>/kubeconfig \
  kubectl get all -n <name>-dev                    # everything in your namespace