Owner References and the Controller Chain
Two numbers tell you whether a controller has caught up with your change, and one field explains why deleting a Pod does not help. The chain runs Deployment to ReplicaSet to Pod, and it is visible in the object itself.
Kubernetes Fundamentals Guide 4 of 46 Beginner
- Kubernetes1.36.4
- kubectlv1.35.2
- TimeAbout 13 min
- Reviewed22 August 2026
Written against the versions above. The API model here has been stable since 1.0. Verbosity flag output format changes between kubectl releases.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| CKA1001 | 192.168.0.175 | Ubuntu 26.04 LTS | Control Plane Node | 2 Core | 4 GB | 50 GB |
| CKA1001-NODE01 | 192.168.0.176 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
Before you start
- A Deployment to inspect. Any will do.
- The Deployments guide from the fundamentals track, for what a rollout is.
-
The two numbers that mean "caught up"
generation 1 observedGeneration 1metadata.generationincrements each time the *spec* changes.status.observedGenerationis the generation the controller has finished acting on. Equal means the controller has seen your latest change.When they differ, the controller is behind - either mid-work or stuck. That is a far better signal than staring at Pod counts, because it distinguishes "still working" from "finished, and this is the result".
Note that only spec changes bump
generation. Annotating metadata, as the previous guide did, changes resourceVersion but not generation - because it asked the controller for nothing new.bash Example session kubectl --context cka1001 -n hpa-demo get deploy cpu-demo -o jsonpath='{.metadata.generation} {.status.observedGeneration}{"\n"}'1 1Expected resultTwo equal numbers.
Success conditionYou can tell whether a controller has caught up with the spec.
-
The chain, from the Pod upwards
A Pod's
ownerReferencesnames what created it:ReplicaSet/cpu-demo-7dd7d449d6Not the Deployment. The chain is Deployment -> ReplicaSet -> Pod, each link a separate controller doing one job: the Deployment controller manages ReplicaSets, the ReplicaSet controller manages Pods.
That indirection is what makes rollouts work at all. A new revision is a *new ReplicaSet*, scaled up while the old one scales down - which is why rollback is fast and why the hash in the name matters.
Two practical consequences. Deleting a Pod achieves nothing - the ReplicaSet recreates it, because its job is to maintain a count. And garbage collection follows these references: delete the Deployment and the ReplicaSet becomes an orphan whose owner is gone, so it is collected, and its Pods with it.
bash Example session kubectl --context cka1001 -n hpa-demo get rs -l app=cpu-demo --no-headers | wc -l1kubectl --context cka1001 -n hpa-demo get pod -l app=cpu-demo -o jsonpath='{.items[0].metadata.ownerReferences[0].kind}/{.items[0].metadata.ownerReferences[0].name}{"\n"}'ReplicaSet/cpu-demo-7dd7d449d6Expected resultOne ReplicaSet, and a Pod owned by it rather than by the Deployment.
Success conditionYou can name the object that owns a given Pod.
Troubleshooting
observedGenerationstays behindgeneration.Why: The controller is not reconciling - crashed, not running, or wedged on this object.
Fix:Check the controller manager Pods, then the object's Events. For a CRD, check the operator that owns it - a stalled generation is the clearest sign an operator is down.
Deleted Pods keep coming back.
Why: Working as intended. The owner recreates them.
Fix:Delete or scale the owner. Follow
ownerReferencesup until you reach something with no owner - that is the thing to change.Old ReplicaSets accumulate.
Why: Kept deliberately, for rollback.
Fix:
spec.revisionHistoryLimitbounds it. The default of 10 is fine; setting it to 0 means nokubectl rollout undo.