The Illustrated Guide to Kubernetes Architecture: Control Planes, Worker Nodes, and Reconciliation Loops
· Sourabh G Kulkarni
Kubernetes is not a container runner—it is a distributed state-reconciliation engine. Here is a clear, illustrated architectural deep dive into how the API server, etcd, scheduler, controllers, kubelet, and kube-proxy collaborate to keep your applications alive.

When engineers first encounter Kubernetes, they often imagine it as a giant, magical operating system that runs Docker containers across a fleet of servers.
That mental model is not just incomplete—it leads to profound confusion the moment a cluster misbehaves.
Kubernetes does not actually run containers directly. It does not monitor containers with cron jobs, and it does not maintain persistent direct communication lines between its components.
Fundamentally, Kubernetes is a distributed, declarative state-reconciliation engine. You submit a specification of what the world should look like, and a set of independent, loosely coupled control loops work asynchronously to make reality match your declaration.
To truly understand Kubernetes—whether you are debugging an incident, preparing for a platform architecture interview, or designing an internal developer platform—you must understand how its components actually talk, who holds authority, and what happens under the hood during the lifecycle of a deployment.
1. The Macro Architecture: Two Realms
A Kubernetes cluster is divided strictly into two functional planes:
- The Control Plane (The Brain): Maintains the cluster's state, evaluates health, takes scheduling decisions, and responds to cluster events.
- Worker Nodes (The Muscle): The compute machines (virtual machines or bare metal) where your actual application containers live and execute.
┌────────────────────────────────────────────────────────────────────────┐
│ THE CONTROL PLANE (BRAIN) │
│ │
│ ┌───────────────┐ ┌────────────────┐ ┌─────────────┐ │
│ │ kube-scheduler│ ◄────► │ kube-apiserver │ ◄────► │ kube- │ │
│ └───────────────┘ └───────┬────────┘ │ controller-│ │
│ │ │ manager │ │
│ ▼ └─────────────┘ │
│ ┌─────────────┐ │
│ │ etcd │ (Distributed Key-Value DB) │
│ └─────────────┘ │
└────────────────────────────────────┬───────────────────────────────────┘
│ HTTPS / TLS gRPC
┌─────────────────────┴─────────────────────┐
▼ ▼
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ WORKER NODE 01 (MUSCLE) │ │ WORKER NODE 02 (MUSCLE) │
│ │ │ │
│ ┌──────────────────────┐ │ │ ┌──────────────────────┐ │
│ │ kubelet │ │ │ │ kubelet │ │
│ └──────────┬───────────┘ │ │ └──────────┬───────────┘ │
│ ▼ │ │ ▼ │
│ ┌──────────────────────┐ │ │ ┌──────────────────────┐ │
│ │ Container Runtime │ │ │ │ Container Runtime │ │
│ │ (containerd / CRI-O) │ │ │ │ (containerd / CRI-O) │ │
│ └──────────┬───────────┘ │ │ └──────────┬───────────┘ │
│ ▼ │ │ ▼ │
│ ┌──────────────────────┐ │ │ ┌──────────────────────┐ │
│ │ [Pod A] [Pod B] │ │ │ │ [Pod C] [Pod D] │ │
│ └──────────────────────┘ │ │ └──────────────────────┘ │
│ │ │ │
│ ┌──────────────────────┐ │ │ ┌──────────────────────┐ │
│ │ kube-proxy │ │ │ │ kube-proxy │ │
│ └──────────────────────┘ │ │ └──────────────────────┘ │
└──────────────────────────────┘ └──────────────────────────────┘
The most important architectural rule in this entire system is this:
The Invariant: No component ever talks directly to
etcdexceptkube-apiserver. Furthermore, worker nodes never talk to each other to coordinate scheduling. All coordination happens strictly through state updates emitted to and watched from the API server.
Let us inspect each component in depth.
2. Inside the Control Plane: The Four Pillars
1. kube-apiserver (The Front Door & Validator)
The API server is the central nervous system of Kubernetes. It exposes a JSON/Protobuf over HTTPS REST API. Everything you do with kubectl, every action an automated CI/CD pipeline takes, and every internal controller check flows through this binary.
When a request arrives at kube-apiserver, it passes through a strict sequential pipeline:
- Authentication: Determines who you are (mTLS certificates, OIDC bearer tokens, Webhook tokens).
- Authorization: Determines if you are allowed to perform the requested verb on the resource (primarily RBAC: Role-Based Access Control).
- Mutating Admission Webhooks: Can modify the object before storage (e.g., automatically injecting an Istio sidecar container or setting default resource requests).
- Schema Validation: Verifies the YAML conforms to the strict API schema.
- Validating Admission Webhooks: Can reject the object based on security policies (e.g., blocking containers running as
rootvia Kyverno or OPA Gatekeeper). - Storage: Only if every check passes, the object is serialized and written to
etcd.
[ Request ] ──► [ AuthN ] ──► [ AuthZ ] ──► [ Mutating ] ──► [ Validate ] ──► [ etcd Write ]
2. etcd (The Single Source of Truth)
etcd is a strongly consistent, distributed key-value store based on the Raft consensus algorithm. It stores the complete specification and status of every resource in the cluster.
Key architectural characteristics:
- Consistent & Partition Tolerant (CP): Under the CAP theorem,
etcdprioritizes consistency over availability. If a network partition prevents a cluster from achieving quorum (majority: $\lfloor n/2 \rfloor + 1$ nodes), writes are rejected to prevent split-brain state corruption. - MVCC (Multi-Version Concurrency Control): It does not overwrite keys in place. Every modification increments a global 64-bit revision counter. This allows controllers to ask: "Tell me everything that changed since revision 40,201."
- Watch API: Instead of controllers polling
etcdthousands of times per second (which would destroy CPU and network capacity),etcdstreams change events over HTTP/2 gRPC streams directly to the API server.
3. kube-scheduler (The Placement Matchmaker)
The scheduler has one job: look for newly created Pods that have no assigned node (spec.nodeName == "") and pick the best worker node for them.
It does not launch the pod. It merely updates the Pod's spec.nodeName field via the API server.
The scheduling decision runs in two distinct phases:
[ Unscheduled Pod ]
│
▼
┌──────────────────┐
│ 1. Filtering │ ──► Discards nodes that cannot fit the pod
│ (Predicates) │ (Insufficient CPU/RAM, NodeSelector mismatch, Taints/Tolerations)
└───────┬──────────┘
│
▼
┌──────────────────┐
│ 2. Scoring │ ──► Ranks remaining candidates 0–100
│ (Priorities) │ (ImageLocality, LeastRequestedPriority, PodTopologySpread)
└───────┬──────────┘
│
▼
[ Selected Node Binding ] ──► Writes assigned nodeName to API Server
- Filtering (Predicates): Filters out nodes that fundamentally cannot host the pod. Checks:
- Does the node have enough allocatable CPU and Memory?
- Does the node match the
nodeSelectorornodeAffinityrules? - Does the pod have tolerations for the node's taints?
- Are requested host ports already bound?
- Scoring (Priorities): Ranks the surviving nodes on a scale of 0 to 100 based on weighted algorithms:
LeastAllocatedPriority: Spreads pods across nodes to balance resource consumption.ImageLocalityPriority: Favors nodes that already cached the container image locally to eliminate download delay.PodTopologySpread: Spreads replicas across failure domains (racks or availability zones) to survive hardware failures.
4. kube-controller-manager (The Infinite Reconciliation Loop)
If the API server is the brain and etcd is the memory, the controller manager is the beating heart.
It is a single binary containing dozens of independent, concurrent control loops. Every controller implements the exact same fundamental logic:
$$\text{Reconcile}() = f(\text{Desired State}, \text{Actual State}) \longrightarrow \text{Action}$$
┌────────────────────────────────────────────────────────┐
│ THE CONTROL LOOP CYCLE │
│ │
│ ┌─────────────────┐ │
│ │ Observe State │ ◄── Watch API Server │
│ └────────┬────────┘ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Analyze Diff │ ── (Desired != Actual?) │
│ └────────┬────────┘ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Take Action │ ── Create/Delete/Patch │
│ └─────────────────┘ │
└────────────────────────────────────────────────────────┘
A few critical built-in controllers include:
- DeploymentController: Watches
Deployments. When a deployment changes, it creates or updates a underlyingReplicaSet. - ReplicaSetController: Ensures the exact number of pod replicas declared in
spec.replicasexist. If you asked for 3 and there are 2, it generates a new Pod object. - NodeController: Monitors worker node heartbeats. If a node stops responding for more than
pod-eviction-timeout(default 5 minutes), it schedules the evacuation of its pods. - EndpointSliceController: Keeps network endpoints up to date as pods spin up or terminate, feeding live IP lists to
kube-proxy.
3. Inside the Worker Node: The Execution Muscle
1. kubelet (The On-Host Captain)
The kubelet is an agent running natively as a systemd service on every worker node. It does not run inside a container.
Its primary responsibility is to watch for Pods assigned to its specific node, instruct the container runtime to launch them, continuously check their health probes (liveness, readiness, startup), and report node status back to the control plane.
Crucially, the kubelet does not know how to run Docker or containerd directly. Instead, it speaks to the container engine over a standardized Unix domain socket using gRPC: the Container Runtime Interface (CRI).
2. The Container Runtime (containerd / CRI-O & runc)
Modern Kubernetes does not use the full Docker daemon. Instead, it speaks directly to lightweight, compliant runtimes like containerd or CRI-O.
When kubelet issues a CRI gRPC call like RunPodSandbox or CreateContainer:
containerdreceives the gRPC instruction.- It calls a low-level OCI runtime, typically
runc. runcinteracts directly with the Linux kernel:- Sets up Linux Namespaces for isolation (
pid,net,mnt,ipc,uts,user). - Sets up cgroups (Control Groups) for resource constraints (
cpu.max,memory.max). - Mounts the root filesystem using an overlay storage driver (
overlay2).
- Sets up Linux Namespaces for isolation (
- Once the process is spawned,
runcexits, leaving a tiny supervisor process calledcontainerd-shimto monitor the container without keepingruncresident in memory.
kubelet ──(gRPC CRI)──► containerd ──► containerd-shim ──► runc ──► Linux Kernel (cgroups/namespaces)
3. kube-proxy (The Network Plumber)
Pods in Kubernetes are ephemeral—they are created, destroyed, and rescheduled with completely new IP addresses constantly. You cannot point clients directly to pod IPs.
Kubernetes solves this with Services (stable virtual IPs). But who routes traffic from a Service IP (10.96.0.100) to the actual healthy Pod IP (172.16.2.45)?
That is the responsibility of kube-proxy.
kube-proxy runs on every node (typically as a DaemonSet). It watches the API server for Service and EndpointSlice updates and translates them into local network routing rules on the host OS:
- iptables mode (default): Translates service IPs by generating
PREROUTINGandKUBE-SERVICESchains in the Linux kernel netfilter. Packet routing uses random probabilistic load balancing. - IPVS mode: Uses Linux IP Virtual Server (hash-table based), scaling efficiently to tens of thousands of services without the linear rule-traversal latency of iptables.
- eBPF (Cilium / modern alternatives): Bypasses kube-proxy and iptables completely, attaching eBPF programs directly to socket layers for zero-overhead packet routing.
4. The 10-Step Journey of a Deployment
To see how all these pieces interlock in real life, let us trace exactly what happens when you type:
kubectl apply -f web-deployment.yaml
[1. kubectl apply] ──► [2. API Server: AuthN/AuthZ/Admit] ──► [3. etcd write]
▲
│ Watch Stream
▼
[4. Deployment Controller creates ReplicaSet]
│
▼
[5. ReplicaSet Controller creates 3 Unbound Pods]
│
▼
[6. kube-scheduler filters & scores nodes]
│
▼
[7. Scheduler binds Pod to Node-01 in etcd]
│
▼
[8. Kubelet on Node-01 receives Pod update]
│
▼
[9. Kubelet calls CRI -> containerd -> runc]
│
▼
[10. Pod is running; Endpoints updated via kube-proxy]
- Client Submission:
kubectlconverts the YAML to JSON and issues anHTTP POST /apis/apps/v1/namespaces/default/deploymentstokube-apiserver. - Admission & Persistence: The API server authenticates the caller, validates RBAC permissions, runs admission webhooks, and writes the
Deploymentrecord toetcd. - Deployment Controller Reacts: The
DeploymentController(insidekube-controller-manager), which maintains an open watch on deployments, sees the new record. It generates a childReplicaSetobject and sends it back to the API server, which writes it toetcd. - ReplicaSet Controller Reacts: The
ReplicaSetControllerdetects its newReplicaSetwithspec.replicas: 3. It notices that 0 pods currently exist. It creates 3 distinctPodobjects with no node assigned (nodeName: "") and posts them to the API server. - Scheduler Steps In: The
kube-schedulerwatches for unbound pods. It detects the 3 pods. For each pod, it runs its Filtering and Scoring algorithms across available worker nodes, selectsnode-01, and issues aBindingAPI call settingpod.spec.nodeName = "node-01". - Kubelet Notices Its Assignment: The
kubeletdaemon running onnode-01maintains a watch on the API server for pods assigned to its node name. It discovers the new pod assignment. - Sandbox & Storage Allocation:
kubelettells the local Container Runtime (e.g.,containerd) to create a Pod Sandbox (the network namespace and infrastructure container). It calls the Container Network Interface (CNI) plugin to assign a cluster IP to the pod. - Image Pull & Container Spawn:
kubeletinstructs the runtime to pull the container image if not cached locally, then invokesruncto spawn the application containers with assigned cgroup memory and CPU limits. - Health Probes Pass:
kubeletmonitors the pod's configuredstartupProbeandreadinessProbe. Once the application returns HTTP 200,kubeletupdates the Pod status toReadyvia the API server. - Traffic Routing Enabled: The
EndpointSliceControllersees the Pod is nowReadyand appends its IP to the matchingServiceendpoint list. On every worker node,kube-proxyimmediately updates its local routing tables (iptables/IPVS/eBPF) so incoming traffic flows seamlessly to the new container.
5. Architectural Summary Table
| Component | Plane | Runs As | Primary Responsibility | Talks Directly To |
|---|---|---|---|---|
kube-apiserver | Control | Static Pod / Binary | Exposes REST API, validates, authenticates, enforces admission | etcd, Controllers, Scheduler, Kubelet |
etcd | Control | Static Pod / Cluster | Consistent distributed storage of cluster state | Only kube-apiserver |
kube-scheduler | Control | Static Pod / Binary | Evaluates nodes and binds unscheduled pods | kube-apiserver |
kube-controller-manager | Control | Static Pod / Binary | Runs reconciliation loops (Deployments, Replicas, Nodes) | kube-apiserver |
kubelet | Worker | Systemd Service | Node supervisor; translates pods to containers via CRI | kube-apiserver, Container Runtime (CRI) |
containerd / CRI-O | Worker | Systemd Service | Manages images, containers, namespaces, cgroups via runc | kubelet, Linux Kernel |
kube-proxy | Worker | DaemonSet Pod | Programs host packet filter rules for Service VIPs | kube-apiserver, Kernel (iptables/IPVS) |
The Big Takeaway
Kubernetes is often criticized for being overly complex. But that complexity is the deliberate result of a powerful design choice: extreme decoupling.
No single component knows the entire story.
- The scheduler does not know how to start a container.
- The controller manager does not know which physical node exists.
- The kubelet does not know why a pod was created or what deployment owns it.
- And
etcddoes not know what any of the data means.
By breaking container orchestration into independent, single-responsibility components communicating through a versioned REST API, Kubernetes achieves unmatched resilience. If the scheduler crashes, running pods keep serving traffic. If a worker node dies, control plane controllers detect the absence and seamlessly rebuild workloads elsewhere.
Once you visualize this dance of watchers, API records, and reconciliation loops, the cluster stops feeling like magic—and starts feeling like one of the most elegant distributed systems ever built.