Anatomy of a Manifest
The Reconciliation Loop
The reconciliation loop is the engine behind Kubernetes self-healing. A controller watches the API server for objects of its type. When it sees a difference between spec and status, it acts. After acting, it writes what it observed back into status. Then it watches again. The loop never stops.
Why build it as a loop rather than a one-shot command? Because the cluster environment is unreliable. Nodes fail, network connections drop, containers crash. A loop that continuously compares desired state to observed state can recover from any failure, automatically, without you intervening.
Creating a Pod to Observe
To see this in action in the simulator, start by creating a simple Pod. You will read its full manifest afterward to understand every section.
nano simple-pod.yamlBuild the manifest field by field. Start with identity:
apiVersion: v1kind: Podmetadata: name: simple-podThen add the spec:
apiVersion: v1kind: Podmetadata: name: simple-podspec: containers: - name: web image: nginx:1.28kubectl apply -f simple-pod.yamlReading the Full Manifest
Once the Pod is running, read its full object back from the API server:
kubectl get pod simple-pod -o yamlThe output is much longer than what you wrote. Kubernetes added a great deal to your original manifest. The key sections to understand are:
metadata now contains fields Kubernetes generated: uid, resourceVersion, creationTimestamp, and possibly annotations injected by admission controllers. You declared only name. Kubernetes filled the rest.
spec is largely what you wrote, but with defaults applied. Kubernetes added dnsPolicy, restartPolicy, terminationGracePeriodSeconds, and more. These are sane defaults you did not need to specify.
status is entirely Kubernetes-written. It contains the current observed state of the Pod. The most important subfields are:
status.phase: the high-level lifecycle stage. It moves fromPendingtoRunningonce containers start.status.conditions: a list of named conditions.PodScheduledbecomesTruewhen a node is assigned.InitializedbecomesTruewhen init containers finish.ContainersReadyandReadybecomeTruewhen all containers pass their readiness checks.status.containerStatuses: per-container details including the image ID pulled, restart count, and the current state (running,waiting, orterminated).
In the kubectl get pod simple-pod -o yaml output, what does status.phase show when the Pod is running correctly?
Try it: kubectl get pod simple-pod -o yaml
Reveal answer
Running. The status.phase field reflects the current stage as observed by the kubelet on the node. Pending means the Pod is waiting to be scheduled or the image is being pulled. Running means at least one container is active.
What Failure Looks Like in Status
If the container image does not exist or cannot be pulled, the Pod does not error out and disappear. It stays alive in the API server, and status tells the full story. The status.phase will be Pending, and status.containerStatuses[0].state.waiting.reason will show ErrImagePull first, then ImagePullBackOff as Kubernetes backs off its retry attempts. The waiting.message field gives the exact error from the container runtime. When a Pod refuses to start, kubectl get pod <name> -o yaml is the first place to look.
To watch the Pod status evolve in real time without reading the full YAML each time:
kubectl get pod simple-pod --watchPress Ctrl+C to stop watching. You will see status columns update as the Pod transitions through phases. This is useful when waiting for a large image to pull.
Why is status stored inside the same object as spec rather than in a separate object?
Reveal answer
Because the object is the unit of consistency. A single API request gives you the complete picture: what you asked for and what Kubernetes observed. Controllers use optimistic concurrency with resourceVersion to write status without ever overwriting the user-managed spec. Two fields in one object, two owners, no conflict.
Cleanup
kubectl delete pod simple-podThe object is removed from etcd. The reconciliation loop for Pods has nothing left to reconcile. The slate is clean for the next exercise.
In the next lesson, you will learn how to generate valid manifests from the CLI instead of writing them from scratch, which eliminates a whole class of syntax errors before they reach the API server.