luisgonc.

← blog ·  July 25, 2026  ·  6 min read

Kubernetes clusters are beautiful things

The background of this site is a Kubernetes cluster that does not exist. Aurora points the same scene at a real one: hue is identity, size is memory, tumble is CPU, distance is pressure, and every lifecycle event gets its own animation.

$ bloat--level 3▰▰▰▱▱Bloatin'

0 words at this level · written by AI, throttled by you

The background of this site is a Kubernetes cluster that does not exist.

I built it as decoration. An ivory octahedron in the middle standing in for me, hex prisms around it for the projects, small cubes orbiting each one, packets running down the links. Nothing is being scheduled. The pods are noise on a timer. It exists to look busy behind text.

The cluster background on this site

Which left me with a fake cluster that looked good and a real one that got a wall of green ticks and some stacked area charts.

A cluster is a beautiful system. At any moment there are things being placed on machines, pulling images, coming up healthy, dying, getting evicted, moving to another node and reforming there, and nobody is directing any of it. Kubernetes clusters are beautiful things and they should be represented beautifully. So I built Aurora: the same visual language as that background, wired to a cluster that is really running.

Closer to weather than to Grafana

Grafana answers questions. You arrive with something specific in mind, you pick a panel, you get a number and a shape over time. The whole interface assumes you showed up with a question.

Aurora assumes you did not. There is nothing to configure and nothing to tune: no time range, no thresholds, no alerts. You put it on a screen and it behaves. If you glance over and something looks wrong, that is a bonus rather than the point.

Four questions, four channels

The hard part of a thing like this is not making it move. It is deciding what each kind of movement is allowed to mean, and then never breaking that rule for a nicer frame.

There are four channels, and they do not fight: hue is identity, size is memory, tumble is CPU, and distance is pressure.

Hue is the namespace

A pod’s colour comes from a stable hash of its namespace, so media is always the same hue wherever it lands. The palette holds sixteen swatches. It used to hold eight, which collides as soon as a cluster has a dozen namespaces, and a legend that shows two different namespaces with the same dot is worse than having no legend at all.

Size is memory

Cube size is the pod’s working set, on a log scale. Pod memory spans three orders of magnitude on a real cluster, so a linear ramp renders everything except the outliers as identical specks. In that clip one pod climbs from 10Mi to 900Mi while its neighbour holds still.

Tumble is CPU

Tumble rate is CPU, and only CPU. This one I got wrong first time round. Pods used to carry a small random rate multiplier, which I added for character, and it meant a completely idle pod could visibly out-spin a busy one. Only the starting angle is random now. The swarm still looks unsynchronised, but two pods spinning alike are working alike.

Distance is pressure

Distance from the node is how close a pod is to its own limit, max(mem/memLimit, cpu/cpuLimit). Hot pods drift outward, so a node full of pods pushing their ceilings reads as a silhouette.

This one deliberately disagrees with size. A 232Mi pod with a 4Gi ceiling is large and sits calm and close in. A 103Mi pod limited to 200Mi is small and is the hottest thing on its node. Absolute size and proximity to death are different questions, and a chart that shows you one usually costs you the other. Pods with no limit set fall back to absolute size, since there is nothing to be close to.

Nodes ask the same two questions

A node’s prism breathes at a rate set by its share of allocatable CPU, roughly 0.3Hz idle up to 1.2Hz saturated.

And the prism is a vessel. An inner hex reaches for the rim as the node’s memory fills. This one stays linear, because node memory already arrives as a share of allocatable rather than as an absolute number.

The control plane plays the same game. The octahedron spins up with CPU, swells its inner solid with memory, and greys, warms and grows a containment ring on the same conditions a worker does. It gets treated as a node, because that is what it is.

Every event gets its own animation

There is no shared generic flash anywhere in it.

Scheduled. A mote detaches from the control plane, arcs down the link to the target node, and blooms into a cube that spirals into the orbit shell. The pod is placed by the scheduler, so it arrives from the scheduler.

Crashloop. An arrhythmic red strobe on a decaying cycle, wobbling the cube off its orbit plane. It persists until the condition clears, and it overrides every other channel while it holds, because imminent death outranks resource pressure.

OOM killed. Implodes to a dense point, then throws a shockwave ring that physically shoves its neighbours out of the way before they ease back.

Migrated. A wireframe ghost arcs across the ring from the old node to the new one, and the cube reforms where it lands. Kubernetes does not have a migration event: it has a pod dying here and an unrelated pod being born there. The server correlates the two by controller inside a thirty second window, so it reads as one thing moving.

NotReady, then recovered. The node stutters, its link frays and goes dark, it desaturates and sags out of the ring plane, and its pods dim and slow to a crawl. Recovery sends motes back out along the link and relights everything they touch.

The quietest thing in it

The small motes travelling along the links are not decoration and they are not throughput. Each one is a kubelet renewing its lease, roughly every ten seconds per node.

Nothing else rides the links at rest, and that restraint is the point. When a kubelet dies it stops renewing immediately, so its link simply falls silent. It goes quiet several seconds before the node greys out, because the Ready condition takes a while to flip. The silence arrives before Kubernetes is willing to say anything is wrong.

The rail

On desktop there is a floating panel over the left of the scene: node and pod counts with aggregate CPU and memory, every namespace with its colour and pod count, and a short list of what just happened. It is desktop only. On a phone it would cover the thing it is describing.

Hovering a namespace previews it, clicking pins it, and you can pin several at once. Focus ghosts rather than hides: the other pods shrink and grey but stay exactly where they are, so you keep the full shape of the cluster while your namespace lights up inside it. Seeing one namespace spread evenly across every node while another sits entirely on one machine is the point, and hiding the rest would throw it away.

And when the server goes away, the scene keeps running on its last known state and recedes into the dark. A dropped connection reads as the cluster going quiet rather than as an error toast. It reconnects with backoff and then animates whatever changed while it was blind, so a pod that died during the outage still dissolves properly instead of just being absent.

See it

The code is on GitHub. It reads whatever context your kubeconfig points at, so you can aim it at any cluster you are allowed to look at.

If you have ever left kubectl get pods -w running in a terminal purely because you liked watching it go, you already know what this is for.