Kubelet Reconcile Loop

How does the Kubelet turn a Pod spec into running containers, and keep them that way? It runs a sync loop that compares the Pod specs it takes from its sources, mainly the API, against what the container runtime reports is actually running on this Node. Whenever the two differ it issues the runtime calls needed to converge, then reports the fresh status back to the API. PLEG is what wakes that loop when a container dies on its own.

Play the animation 5 steps, animated, best on a wide screen

Kubelet Reconcile Loop diagram: Kubelet sync loop

Kubelet Reconcile Loop, step by step

  1. The API streams an ADDED event for Pod my-app-7d4-x2k9p bound to Node-1. The Kubelet merges its spec sources into one update channel, and the sync loop records the Pod in podManager as desired state.

    Play from step 1
  2. PLEG (Pod Lifecycle Event Generator) wakes on its 1s timer, calls ListPodSandbox and ListContainers, and finds no sandbox or container for the new Pod. The empty observed state is recorded for SyncPod. The EventedPLEG feature gate (alpha, off by default) has the runtime push lifecycle events over CRI, so the Kubelet relists far less often.

    Play from step 2
  3. The sync loop queued the Pod for its Pod worker goroutine, which now calls SyncPod. SyncPod compares desired state (1 container in spec) against observed state (no sandbox, 0 containers). The diff is two actions: create the Pod sandbox, then create and start the missing container.

    Play from step 3
  4. Kubelet issues CRI gRPC calls in sequence: RunPodSandbox creates the pause container with shared namespaces, PullImage fetches the image, which imagePullPolicy can skip when it is already on the Node, then CreateContainer and StartContainer launch each container in the spec. Details of the sandbox setup are covered in the Pod Sandbox via CRI card.

    Play from step 4
  5. Right after that sync the Kubelet asks PLEG to relist the Pod (beta PLEGOnDemandRelist, on by default), so it sees the running container without waiting for the 1s timer. Observed state catches up to desired state, SyncPod finds nothing left to create or start, and Kubelet PATCHes Pod status again, now with the running container in containerStatuses.

    Play from step 5

Sources