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
| Value | Default | Meaning |
|---|---|---|
clusterName | in-cluster | Name in the top bar |
timeZone | UTC | Time zone for the panels |
prometheus.address | <namespace>/<service>:<port> of Prometheus with Traefik metrics | |
networkPolicy.apiServer.cidrs | API server endpoints, see below | |
networkPolicy.prometheus.podLabels | Labels of the Prometheus pods | |
ingress.enabled, ingress.host | off | Ingress for the web UI |
imagePullSecrets | For a private registry | |
resources | 50m / 160Mi, max 1 CPU / 512Mi | Requests 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. Escgoes back,hjumps to the harbor andfshows 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,
Escends it. Add?nowizardto 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
| Kind | Building | Pods as |
|---|---|---|
| Deployment | Factory with sawtooth roof | Presses |
| StatefulSet | Data works, one tank per replica | Data tanks |
| DaemonSet | Relay station with mast and dish | Radio cabinets |
| ReplicaSet without owner | Workshop with gable roof | Workbenches |
| Job | Round-roofed hangar | Mixer drums |
| CronJob | Clock tower works, real time | Timer boxes |
| Pod without owner | Open shelter | Generator carts |
| PersistentVolumeClaim | Storage hall with racks | |
| Ingress | Loader at the loading bay | |
| Node | Power plant by the river | |
| Anything else | Generic hall | Blocks |
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.