Kubernetes Spec and Status Model
Kubernetes Spec and Status Model defines desired and current states, enabling dynamic management of containerized applications in clusters.
Kubernetes Spec and Status Model is the foundational design pattern underlying almost every controller in the system: representing desired state and observed state as two separate, independently writable fields on the same object, and treating the ongoing work of a controller as nothing more than continuously driving the gap between them toward zero. This pattern, more than any individual API mechanism, is what makes Kubernetes controllers composable, restart-safe, and resilient to missed updates, since a controller never needs to process every historical event correctly — it only needs to look at spec and status as they currently stand and decide what to do next.
Spec as a Declaration, Not a Command
What Belongs in Spec
Spec fields describe an end state a client wants to exist — three replicas, a specific container image, a particular storage size — never a sequence of steps to get there; a Deployment's spec never says "start one more Pod," it says "there should be three Pods," leaving entirely to the controller how to get from whatever the current count is to that target.
Why This Distinction Matters
Because spec expresses an end state rather than a command, submitting the same spec twice is harmless — the controller simply observes that the desired state already matches reality and does nothing further — whereas an imperative "start one more Pod" command issued twice would produce a different, likely undesired, outcome; this idempotence is what allows clients to safely retry writes without needing to track whether an earlier attempt already succeeded.
Status as an Observation, Not a Cache
Status Should Be Re-Derivable
By convention, a well-behaved controller's status is fully re-computable from the current state of whatever the controller is watching; if a controller's in-memory state were wiped and it started fresh, it should be able to observe the world again and reconstruct the same status, meaning status is not a persisted decision log but a live summary of what is currently true.
The Consequence for Controller Restarts
This re-derivability is precisely what allows a controller to be killed and restarted at any point without corrupting cluster state: on restart, it simply lists the current objects it manages, recomputes status from their current condition, and resumes reconciling, with no special recovery logic required for the interruption itself.
The Reconciliation Loop Pattern
Level-Triggered, Not Edge-Triggered
Kubernetes controllers are designed to be level-triggered rather than edge-triggered: rather than reacting only to the specific event that changed (an update, say), a controller re-evaluates the full current spec against the full current status every time it runs, regardless of what specific change triggered the run; this means a missed or coalesced event does not leave the system in a permanently wrong state, since the next reconciliation, triggered by anything, will still notice and correct any outstanding gap.
Why Level-Triggering Tolerates Failure
Because reconciliation always compares current spec to current status rather than replaying a sequence of past events, a controller that crashes mid-reconciliation, misses a watch event due to a network blip, or restarts after an outage will simply reconcile again from scratch the next time it runs, converging to the same correct outcome it would have reached without the interruption.
Multiple Controllers, One Object
Division of Responsibility by Field
Some objects have spec and status written by different actors entirely — a PersistentVolumeClaim's spec is written by the requesting user while its status (bound or pending) is written by the volume binding controller — and this division, enforced through the status subresource and RBAC, is what allows multiple independent controllers or a user and a controller to safely co-manage different portions of a single object without one accidentally overwriting the other's authoritative field.
Downstream Status Propagation
Status fields are frequently consumed as the effective input to a different controller's reconciliation — an EndpointSlice controller reads Pod status conditions to build Service endpoints — meaning status on one object often functions as part of the desired-state or observed-state computation for an entirely separate controller, chaining spec/status pairs together into the layered reconciliation graph that gives the whole platform its emergent, self-healing behavior.