Controller Pattern
A controller is a loop that watches the declared desired state of a resource, observes actual state, and takes the minimum action to close the gap. It runs continuously and never terminates (Kubernetes docs).
Structure
loop:
desired ← read spec
actual ← observe reality
diff ← compare(desired, actual)
if diff ≠ ∅:
act(diff)
This is the reconciliation loop from desired state systems made concrete. The controller is the closed-loop feedback mechanism — the sensor, comparator, and actuator in one component (xettel).
Properties
- Idempotent — applying the same desired state repeatedly converges to the same result
- Level-triggered — the controller reacts to the current state of the world, not to the event that changed it. If it misses an event, it still converges on the next observation (Jenco)
- Decoupled — the controller acts through an API (e.g. Kubernetes API server), not by directly manipulating the underlying system
Composition
Controllers compose: one controller’s output becomes another’s input. A Deployment controller creates ReplicaSets; the ReplicaSet controller creates Pods; the kubelet runs containers. Each level is a separate controller with its own reconciliation loop (Kubernetes docs).
Beyond Kubernetes
The pattern is not specific to Kubernetes. Any desired state system with continuous reconciliation implements it: thermostats, Terraform with drift detection, GitOps agents, even goal-setting in management (where the “controller” is a human checking progress against a target).
In control theory terms, the watch-diff-reconcile pattern is a simplified PID controller operating in P-only mode — it reacts to the current error without accumulating history or predicting rate of change (Wikipedia).