kubeside

Fleet

Is every cluster running the latest version? One app, one row per cluster.

Fleet

Promotion compares environments side by side. Fleet answers a question promotion cannot phrase: a team running prod across two regions, or any environment holding more than one cluster, needs to know whether those clusters agree with each other, not only whether prod agrees with stg.

Opening it

Four ways in:

Opening this screen wakes every context in your kubeconfig, not only the one you were looking at. The app list and app detail connect lazily, one context at a time, as you look at them. Fleet asks all of them at once, on open, because "every cluster" is the question it exists to answer.

Promotion also connects every context, so fleet is not alone in that. Two things make fleet heavier. It connects them concurrently rather than one after another, and it reads pod status on every cluster it reaches, which promotion does only for the apps you are comparing. Pod status is where the image digest lives, and the digest is what catches one tag running as two different builds.

On a kubeconfig with forty contexts, that is forty connections at once, each possibly running a credential plugin. Worth knowing before you bind the palette command to muscle memory.

Reading the table

State Means
present The cluster runs the app.
absent The cluster answered, and does not run it. A schedule, not a problem: the app just is not deployed there yet.
denied The cluster refused the read. The note names the RBAC rule that would fix it, for example "cannot read Deployment here; the role needs: list deployments in team-a".
unreachable The cluster did not answer at all. VPN, DNS, or the cluster is down.
pending Still asking.

The distinction that matters most is unreachable against absent. A prod cluster reachable only over VPN, currently off, is unreachable: kubeside never saw it this time, so it never claims the app is missing there. Only a cluster that actually answered and does not run the app gets absent. Conflating the two, "I could not look" read as "it is not there", is the mistake this screen exists to prevent, and it is the reason opening fleet wakes every context instead of trusting whatever was last connected.

A present row can also carry:

Rows sort by how much the cluster told you, worst first: mutable tag, then unreachable, then behind, then denied, then present with no comparable version, then pending. Absent sits with the healthy rows at the bottom, because "not deployed here" is not a disagreement.

Version unknown

An image pinned by digest (myapp@sha256:...) carries no tag. There is nothing to compare it against, so the row reads "version unknown: the image is pinned by digest" rather than folding it into the newest tag or treating it as a match. Pinning by digest is not a defect; reading it as agreement would be.

Clusters that are really one cluster

A kubeconfig commonly holds one cluster under two context names, often because one of them carries credentials that stopped working. Fleet detects this by API server URL and merges the two into one row, so the same cluster is never counted twice. The row names what it merged: "also prod-us-east-arn" beside the context it kept. The row it keeps is whichever context answered with the most, so a stale duplicate never hides a live one.