Documentation

KubeYard is a single pod that reads your cluster and draws it as a city. The only thing it needs is a read-only service account. If you have Prometheus with Traefik metrics, KubeYard can also show the request traffic.

KubeYard is in early beta. If you find a bug or have an idea, please write to info@lixsl.net.

Install with Helm

kubectl create namespace kubeyard
kubectl label namespace kubeyard pod-security.kubernetes.io/enforce=restricted
helm install kubeyard oci://registry-1.docker.io/lixsl/kubeyard-chart -n kubeyard \
  --set clusterName=prod --set timeZone=Europe/Berlin
kubectl -n kubeyard port-forward svc/kubeyard 8011:80

Then open http://127.0.0.1:8011. If you want a fixed address, set ingress.enabled=true and ingress.host.

If you don't use Helm, there is also a single install.yaml for the latest release. It creates the namespace and uses the default values:

kubectl apply -f https://kubeyard.net/install.yaml

Run on your laptop

You need kubectl and Docker. The script creates a read-only account in the cluster once. After that it starts the KubeYard image with a token for that account that is valid for 12 hours, so your own credentials are never used. The container runs without root, with a read-only file system and only on localhost.

curl -fsSLO https://kubeyard.net/kubeyard.sh && chmod +x kubeyard.sh
./kubeyard.sh setup <context>    # once per cluster
./kubeyard.sh <context>          # start on http://127.0.0.1:8011
./kubeyard.sh remove <context>   # delete the account again
./kubeyard.sh --demo             # fake cluster, no kubectl needed

Your kubeconfig stays on your machine. The container talks to a local kubectl proxy that uses the read-only token, so it also works with local clusters like kind, k3d or OrbStack, and with clusters that log in through a plugin. Set PORT for another port than 8011.

Chart values

ValueDefaultMeaning
clusterNamein-clusterName in the top bar
timeZoneUTCTime zone for the panels
prometheus.address<namespace>/<service>:<port> of Prometheus with Traefik metrics
networkPolicy.apiServer.cidrsAPI server endpoints, see below
networkPolicy.prometheus.podLabelsLabels of the Prometheus pods
ingress.enabled, ingress.hostoffIngress for the web UI
imagePullSecretsFor a private registry
resources50m / 160Mi, max 1 CPU / 512MiRequests and limits of the pod

Network policy

All traffic in the namespace is blocked by default. KubeYard accepts connections on port 8080 and can only connect to DNS, the API server and Prometheus. Network policies see the real address of the API server, not the service IP. If you don't set apiServer.cidrs, any address is allowed on the API server ports. To limit it to your API server:

kubectl get endpointslice -n default -l kubernetes.io/service-name=kubernetes \
  -o jsonpath='{range .items[*]}{.endpoints[*].addresses[0]}{" port "}{.ports[*].port}{"\n"}{end}'
helm upgrade kubeyard ... --set networkPolicy.apiServer.cidrs={10.0.0.1/32}

The policy only allows the usual API server ports, 443 and 6443. If your API server listens on another port (OrbStack uses 26443, for example), KubeYard logs Cannot reach the cluster yet: Connection refused. Add the port that the command above shows:

helm upgrade kubeyard ... --set networkPolicy.apiServer.ports={26443}

Traffic

The request traffic comes from Prometheus with Traefik metrics (traefik_service_requests_total, traefik_service_request_duration_seconds). The machines produce boxes at the real request rate and failed requests go to the scrap bin. When a service gets more than 2.5 times its usual load, the boxes start to pile up. Without Prometheus the machines still run, based on the CPU usage of their pods from metrics-server.

Using the city

  • Drag to move, scroll to zoom and click on anything to see its details. Press / to search, then use the arrow keys and Enter to pick a result.
  • Esc goes back, h jumps to the harbor and f shows the whole city.
  • The namespace picker shows only one namespace and hides the rest of the city.
  • The screen button starts kiosk mode for wall screens, Esc ends it. Add ?nowizard to the URL to skip the setup on the first visit.
  • KubeYard can be installed as an app. On an iPad or iPhone open it in Safari, then Share and "Add to Home Screen". In Chrome or Edge use the install button in the address bar. It then starts full screen, which suits kiosk mode on a wall screen.
  • The gear opens the settings: light or dark theme, blue halls or one color per namespace, real time of day or always day. The settings are saved in your browser.

Kinds

KindBuildingPods as
DeploymentFactory with sawtooth roofPresses
StatefulSetData works, one tank per replicaData tanks
DaemonSetRelay station with mast and dishRadio cabinets
ReplicaSet without ownerWorkshop with gable roofWorkbenches
JobRound-roofed hangarMixer drums
CronJobClock tower works, real timeTimer boxes
Pod without ownerOpen shelterGenerator carts
PersistentVolumeClaimStorage hall with racks
IngressLoader at the loading bay
NodePower plant by the river
Anything elseGeneric hallBlocks

Security

The service account can only get, list and watch nodes, namespaces, pods, services, events, PVCs, workloads, ingresses, autoscalers and metrics. On startup KubeYard uses SelfSubjectAccessReview to check that it can't create, delete or patch anything, can't exec into pods, can't read logs or secrets, can't use the node proxy and can't escalate. If any of these checks fail, it does not start. Inside the app, a request filter only lets GET requests on these paths through. The browser never talks to the cluster directly, it only gets the data it needs to draw the city.

The image is based on a chiseled .NET runtime with no shell and no package manager. It runs as user 1654 with a read-only root file system, no capabilities and seccomp. The namespace has a resource quota, and the pod has a priority below zero, so it never pushes other pods off a node.