You don’t need to memorize every piece. You need to understand why each one exists — and what breaks when it’s gone.
Kubernetes Zero to Hero · Episode 02
In Episode 1, we talked about what Kubernetes is and the pain it solves. If you haven’t read it yet, go start there — this article picks up right where that one left off.
Now we go deeper. Before you can confidently deploy applications, debug failures, or design resilient systems on Kubernetes, you need a mental model of how the platform itself is built. Not memorized facts — an actual intuition for what each component does, who it talks to, and why it matters.
By the end of this article, you’ll be able to look at any Kubernetes cluster and reason about what’s happening inside it.
The Big Picture: Two Sides of Every Cluster
Every Kubernetes cluster is divided into two logical groups of machines:
The Control Plane — the brain. It makes all the decisions. It doesn’t run your application workloads. It runs the software that manages your workloads.
The Worker Nodes — the muscle. This is where your application containers actually execute. A node is simply a machine — physical or virtual — registered with the control plane.
Think of it like a logistics company. The control plane is headquarters: planning, scheduling, monitoring, and dispatching. Worker nodes are the warehouses and delivery trucks: they do the physical work, but they take direction from HQ.
┌─────────────────────────────────────────────────────┐
│ CONTROL PLANE │
│ API Server · etcd · Scheduler · Controller Manager │
└──────────────────────┬──────────────────────────────┘
│ manages
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Worker │ │ Worker │ │ Worker │
│ Node 1 │ │ Node 2 │ │ Node 3 │
│ │ │ │ │ │
│ kubelet │ │ kubelet │ │ kubelet │
│ kube-proxy │ │ kube-proxy │ │ kube-proxy │
│ container │ │ container │ │ container │
│ runtime │ │ runtime │ │ runtime │
└────────────┘ └────────────┘ └────────────┘
Let’s walk through each component — starting with the control plane.
The Control Plane
1. The API Server — The Front Door to Everything
What it is: The single point of entry for all communication in a Kubernetes cluster. Every action — from kubectl apply to a kubelet reporting pod status — goes through the API Server.
What it does:
- Exposes the Kubernetes REST API
- Authenticates and authorizes every request
- Validates and persists objects to
etcd - Acts as the communication hub between all other components
Why it matters: The API Server is the only component that talks directly to etcd. Every other component — the scheduler, controller manager, kubelets — communicates exclusively through the API Server. This design means you get a single, auditable, access-controlled gateway for the entire cluster.
# Everything you do with kubectl goes through the API Server
$ kubectl get pods
# ↑ This sends a GET request to: https://<api-server>/api/v1/namespaces/default/pods
💡 If the API Server goes down, you can’t make changes to the cluster. However, workloads already running on nodes continue running — the cluster keeps serving traffic even with a dead control plane. This is an important property: read-only resilience.
2. etcd — The Source of Truth
What it is: A distributed, strongly-consistent key-value store. It is the only place where cluster state is persisted.
What it stores: Everything. Every pod definition, every secret, every configmap, every node registration, every service, every deployment spec — all of it lives in etcd.
What it does NOT do: etcd doesn’t make decisions. It doesn’t know what a pod is. It’s a database. It stores and retrieves data reliably, with strong consistency guarantees across a cluster of etcd nodes.
Why it matters: Lose etcd without a backup and you lose your entire cluster state. In production, etcd is always run as a multi-node cluster (typically 3 or 5 nodes) for fault tolerance. Back up etcd religiously. We'll dedicate a future article to this.
# You rarely interact with etcd directly, but you can inspect it via the API Server
$ kubectl get all -A # reads from etcd via the API Server
⚠️ etcd uses the Raft consensus algorithm. For a cluster of N nodes, it can tolerate (N-1)/2 failures. This is why you always run an odd number: 3 nodes tolerates 1 failure, 5 nodes tolerates 2.
3. The Scheduler — The Matchmaker
What it is: The component that decides which node a newly created pod should run on.
What it does:
- Watches the API Server for pods with no assigned node (
nodeNameis empty) - For each unscheduled pod, runs a two-phase algorithm: filtering (which nodes can run this pod?) and scoring (which node should run this pod?)
- Writes the selected node back to the pod spec via the API Server
Filtering considers:
- Does the node have enough CPU and memory?
- Does the node have the required labels (node selectors)?
- Does the pod have a toleration for the node’s taints?
- Are there any affinity/anti-affinity rules?
Scoring considers:
- Spread pods across nodes for resilience
- Prefer nodes with the container image already cached
- Balance resource utilization
Why it matters: The scheduler is pluggable — you can replace it or run multiple schedulers for specialized workloads (GPU scheduling, batch jobs, etc.). Understanding scheduling is key to diagnosing Pending pods, one of the most common issues beginners hit.
# A pod stuck in Pending? The scheduler couldn't find a suitable node.
$ kubectl describe pod <pod-name>
# Look for "Events" at the bottom — the scheduler writes its reasons there
# Example: "0/3 nodes are available: 3 Insufficient memory"
4. The Controller Manager — The Reconciliation Engine
What it is: A single binary that runs multiple controllers — each one a control loop responsible for a specific type of Kubernetes object.
The core idea — the reconciliation loop:
while true:
desired_state = read from API Server
actual_state = observe the real world
if desired_state != actual_state:
take action to close the gap
This loop is the heartbeat of Kubernetes. It’s what makes the platform self-healing. It never stops running.
Controllers running inside the Controller Manager:
Controller → What it watches → What it does
ReplicaSet Controller → ReplicaSets → Creates/deletes pods to match desired replica count
Deployment Controller → Deployments → Creates/updates ReplicaSets for rolling updates
Node Controller → Nodes → Detects when nodes go offline; marks pods for rescheduling
Service Account Controller → Namespaces → Creates default service accounts in new namespaces
Endpoints Controller → Services + Pods → Populates the Endpoints object with pod IPs
Job Controller Jobs Creates pods for batch jobs; tracks completion
Why it matters: The controller manager is why you almost never manually create pods. You create a Deployment (a declaration of desired state), and the Deployment controller creates and manages pods on your behalf, forever. This separation of intent from execution is the architectural heart of Kubernetes.
5. Cloud Controller Manager (optional)
If your cluster runs on a cloud provider (AWS, GCP, Azure), this component bridges Kubernetes with cloud-specific resources — load balancers, storage volumes, node lifecycle. It separates cloud-provider logic from the core Kubernetes codebase. On-premises clusters don’t need it.
The Worker Node Components
Every worker node runs three core components. Together they turn a plain machine into a fully functioning Kubernetes node.
1. kubelet — The Node Agent
What it is: An agent that runs on every worker node. It is the single component responsible for making sure containers described in pod specs are actually running and healthy on that node.
What it does:
- Registers the node with the API Server
- Watches the API Server for pods assigned to its node
- Talks to the container runtime to start, stop, and monitor containers
- Reports pod status and node resource usage back to the API Server
- Runs liveness and readiness probes
What it does NOT do: The kubelet doesn’t manage containers it didn’t create. If you manually start a Docker container on a Kubernetes node, the kubelet ignores it.
# Check kubelet status on a node (if you have SSH access)
$ systemctl status kubelet
# See what the kubelet sees — events for a pod on that node
$ kubectl describe pod <pod-name> -n <namespace>
💡 The kubelet is the only control plane-adjacent component that runs on worker nodes. Every node has one. If the kubelet dies on a node, that node goes dark — the control plane stops receiving status updates and eventually marks its pods for rescheduling.
2. kube-proxy — The Network Plumber
What it is: A network proxy that runs on every node and implements the Kubernetes Service concept at the network level.
What it does: When you create a Service, kube-proxy programs network rules (typically iptables or ipvs rules) on every node so that traffic destined for the Service's virtual IP gets routed to a healthy pod backing that Service.
The key insight: Kubernetes Services have a stable virtual IP that never changes, even as the pods behind them come and go. kube-proxy maintains the mapping from virtual IP → real pod IPs in real time.
Client → Service IP (10.96.0.1:80)
↓ [kube-proxy iptables rules]
Pod A (10.244.1.5:8080) ← randomly selected
Pod B (10.244.2.3:8080) from healthy backends
Pod C (10.244.3.7:8080)
Why it matters: Without kube-proxy, Services don’t work. It’s invisible when healthy, and catastrophic when not. If you’re seeing inconsistent traffic routing or Services not resolving, kube-proxy is often where you look.
3. Container Runtime — The Engine Under the Hood
What it is: The software that actually runs containers on a node. The kubelet doesn’t know how to start containers itself — it delegates to the container runtime via the Container Runtime Interface (CRI).
Common runtimes:
containerd— the default in most modern clusters (Docker itself uses containerd under the hood)CRI-O— a lightweight runtime, popular with OpenShiftDocker Engine— was common historically; Kubernetes removed direct Docker support in v1.24 (but containerd still runs your Docker images)
Why this matters: The CRI abstraction means Kubernetes doesn’t care which runtime you use — it only cares that the runtime implements the standard interface. This is a good example of Kubernetes’ plugin-first philosophy.
# Check which runtime your nodes are using
$ kubectl get nodes -o wide
# Look at the CONTAINER-RUNTIME column
# e.g. containerd://1.7.2
Add-ons: The Components That Make a Cluster Usable
The components above are the bare minimum for a functioning cluster. In practice, every real cluster also runs these add-ons:
CoreDNS — Service Discovery
Runs as pods in the cluster. Provides DNS resolution for Services and pods. When your app connects to my-service.default.svc.cluster.local, CoreDNS resolves it to the Service's ClusterIP. Without CoreDNS, services can't find each other by name.
CNI Plugin — Pod Networking
The Container Network Interface plugin gives every pod a unique IP address and enables pod-to-pod communication across nodes. Popular choices: Flannel (simple, good for learning), Calico (production-grade, supports NetworkPolicy), Cilium (eBPF-based, excellent for large-scale clusters).
# See CoreDNS running in your cluster
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5dd5756b68-4xvqk 1/1 Running 0 2d
coredns-5dd5756b68-8wmlk 1/1 Running 0 2d
How It All Fits Together: Tracing a kubectl apply
The best way to cement this architecture is to trace exactly what happens when you run kubectl apply -f deployment.yaml. Every component plays a role.
Step 1 — kubectl → API Server kubectl serializes your YAML into a JSON API request and sends it to the API Server over HTTPS. The API Server authenticates your credentials, checks your RBAC permissions, validates the manifest schema, and writes the Deployment object to etcd.
Step 2 — Controller Manager detects the new Deployment The Deployment Controller is watching the API Server for new Deployment objects. It sees yours. It creates a ReplicaSet object (also written to etcd via the API Server). The ReplicaSet Controller sees the new ReplicaSet and creates the required number of Pod objects — initially with no node assigned.
Step 3 — Scheduler assigns nodes The Scheduler is watching for pods with no nodeName. It finds your new pods, runs its filtering and scoring algorithm, and writes the chosen node name to each pod spec.
Step 4 — kubelet starts containers The kubelet on each selected node is watching the API Server for pods assigned to it. It sees the new pod assignment, calls the container runtime (e.g. containerd) to pull the image and start the container, then reports the pod status back to the API Server.
Step 5 — kube-proxy updates routing rules If your deployment is backed by a Service, kube-proxy detects the new pod IPs via the Endpoints controller and updates iptables rules on every node so traffic to the Service reaches the new pods.
Total time from kubectl apply to running pod: typically 5–30 seconds.
kubectl apply
↓
API Server → etcd (persist Deployment)
↓
Deployment Controller → creates ReplicaSet
↓
ReplicaSet Controller → creates Pods (unscheduled)
↓
Scheduler → assigns Pods to Nodes
↓
kubelet (on node) → container runtime → container running
↓
kube-proxy → updates network rules
The Components at a Glance
Component → Lives on → Responsibility
API Server → Control Plane → Single gateway; all reads/writes go here
etcd → Control Plane → Persistent store for all cluster state
Scheduler → Control Plane → Assigns unscheduled pods to nodes
Controller Manager → Control Plane → Runs reconciliation loops for all object types
Cloud Controller Manager → Control Plane → Cloud provider integration (optional)
kubelet → Every Worker Node → Ensures assigned pods are running and healthy
kube-proxy → Every Worker Node → Implements Service networking via iptables/ipvs
Container Runtime → Every Worker Node → Actually starts and stops containers
CoreDNS → Worker Nodes (as pods) → DNS-based service discovery
CNI Plugin → Every Node → Pod networking and IP allocation
What Breaks When Components Fail
Understanding failure modes separates engineers who know Kubernetes from those who truly understand it:
API Server goes down: You can’t kubectl anything. No new deployments, no scaling. However, running workloads continue unaffected — pods keep serving traffic. The cluster runs blind but keeps moving.
etcd goes down: If the API Server can’t reach etcd, it can’t serve reads or writes. Same operational impact as the API Server going down. Data-loss risk if etcd loses quorum and you have no backup.
Scheduler goes down: New pods get created but stuck in Pending forever — nobody assigns them to nodes. Running pods are fine.
Controller Manager goes down: Reconciliation stops. Crashed pods don’t get replaced. Desired replica counts aren’t enforced. The cluster slowly drifts from desired state.
kubelet goes down on a node: That node goes dark. Eventually the Node Controller marks its pods for rescheduling on healthy nodes. Containers on that node keep running (briefly) but are no longer managed.
kube-proxy goes down on a node: New Service routing rules stop being applied on that node. Traffic to Services from that node may start failing or becoming stale.
Hands-On: Exploring Your Cluster’s Components
# See all control plane and system components
$ kubectl get pods -n kube-system
# Check the health of control plane components
$ kubectl get componentstatuses
# (deprecated in newer versions, but still works on most clusters)# Inspect a node — see kubelet version, container runtime, capacity
$ kubectl describe node <node-name># Check which API resources are available (served by the API Server)
$ kubectl api-resources# See what's running on the control plane (if using kubeadm)
$ kubectl get pods -n kube-system | grep -E 'etcd|apiserver|scheduler|controller'
What’s Next
Now that you have a solid mental model of the architecture, we’re ready to get hands-on with the objects you’ll work with every day.
In Episode 3, we go deep on Pods, Deployments, and ReplicaSets — the holy trinity of Kubernetes workloads. We’ll cover how pods are defined, why you almost never create them directly, how Deployments manage rolling updates, and how ReplicaSets ensure your desired replica count is always maintained.
Episode Topic
EP 01 Introduction to Kubernetes
EP 02 ← You are here Kubernetes Architecture & Components
EP 03 Pods, Deployments & ReplicaSets — The holy trinity
EP 04 Services & Networking — Making pods talk to the world
EP 05 ConfigMaps, Secrets & Environment Config
EP 06 Storage: PersistentVolumes & StatefulSets
EP 07 Ingress Controllers & Load Balancing
EP 08 RBAC & Security Fundamentals
EP 09 Monitoring with Prometheus & Grafana
EP 10 Production Hardening & Helm Charts
Before the Next Article
Try exploring your cluster’s internals with the commands above. Specifically:
# 1. List all system pods and notice which node they run on
$ kubectl get pods -n kube-system -o wide
# 2. Pick any pod and describe it — trace the Events section
$ kubectl describe pod <any-system-pod> -n kube-system# 3. Look at a node's full description — spot the kubelet version and runtime
$ kubectl describe node $(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')
If you can read those outputs and map each field back to the components we covered today, you’re thinking like a Kubernetes engineer.
Architecture is just the beginning. In the next episode, we get our hands dirty — creating workloads, watching reconciliation happen in real time, and deliberately breaking things to see how Kubernetes heals itself.