Kubernetes Architecture: Control Plane and Node
Before typing the first command, we should know what we're talking to. A Kubernetes cluster splits into two clear parts: the control plane — the brain that makes decisions, and the nodes — where applications actually run. Understand this diagram once and every kubectl command from here on has a place to sit.
This series doesn't dig deep into each component's internals (how etcd reaches consensus, how the scheduler scores nodes...) — that's for a later deep-dive series. Here we grasp the role of each piece and how they coordinate.
The big picture
┌──────────────── CONTROL PLANE (the brain) ────────────┐
│ │
kubectl ──(YAML)──► │ kube-apiserver ◄──► etcd (stores cluster state) │
│ ▲ │
│ │ scheduler (picks a node for the pod) │
│ │ controller-manager (keeps desired state) │
└────────┼──────────────────────────────────────────────┘
│ (commands down to nodes)
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌─── NODE 1 ───┐ ┌─── NODE 2 ───┐ ┌─── NODE 3 ───┐
│ kubelet │ │ kubelet │ │ kubelet │
│ kube-proxy │ │ kube-proxy │ │ kube-proxy │
│ [container] │ │ [container] │ │ [container] │
└──────────────┘ └──────────────┘ └──────────────┘
The golden rule to remember: everything goes through kube-apiserver. kubectl never talks directly to a node; it sends requests to the API server. The other components do the same. The API server is the single gateway in and out of the cluster.
Control plane: the brain
Four main components, each with one job:
- kube-apiserver — the cluster's front door. Every command (
kubectl, the controllers, kubelet) goes through here. It receives requests, authenticates, validates, then writes to etcd. It's the only component that talks directly to etcd. - etcd — the key-value database that stores the entire state of the cluster: what you declared, what's currently running. If the cluster is a body, etcd is its memory. Lose etcd and you lose the cluster — so in production it's backed up carefully.
- kube-scheduler — when a new pod hasn't been assigned a node, the scheduler decides which node it runs on, based on free resources, constraints, affinity... It only picks; it doesn't start the container itself.
- kube-controller-manager — runs the control loops (remember Article 0): continuously comparing desired state with actual state and acting to reconcile them. For example, the ReplicaSet controller ensures "want 3 copies, always have 3".
(In the cloud there's also a cloud-controller-manager to talk to the provider's infrastructure — creating load balancers, volumes... On minikube we don't need to worry about it.)
Node: where applications run
A node is a machine (real or virtual) that runs your workloads. Each node has:
- kubelet — Kubernetes' "agent" on each node. It gets the list of pods to run on its node from the API server, then instructs the container runtime (Docker/containerd) to start the containers, and reports health back to the control plane.
- kube-proxy — handles networking: it maintains the network rules so a Service (Article 5) routes traffic to the right pods, even when the pods change. This is the piece that makes "one stable address for many pods" work.
- container runtime — the software that actually runs containers (containerd, CRI-O, or Docker). Kubernetes talks to it through the CRI standard.
A nice detail: the control plane components themselves in minikube also run as pods — Kubernetes runs itself. We can see that right away.
Inspecting the real architecture in minikube
kubectl cluster-info shows where the control plane is running:
Kubernetes control plane is running at https://127.0.0.1:50639
CoreDNS is running at https://127.0.0.1:50639/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
And here's the interesting part — listing the pods in the kube-system namespace (where the system components live), we see exactly the names we just learned:
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7d764666f9-4hhdj 1/1 Running 0 37s
etcd-minikube 1/1 Running 0 43s
kube-apiserver-minikube 1/1 Running 0 43s
kube-controller-manager-minikube 1/1 Running 0 44s
kube-proxy-npmxl 1/1 Running 0 37s
kube-scheduler-minikube 1/1 Running 0 43s
storage-provisioner 1/1 Running 0 42s
The whole brain sits right here: etcd, kube-apiserver, kube-controller-manager, kube-scheduler, kube-proxy. Two more worth mentioning:
- coredns — the cluster's internal DNS. Thanks to it, a pod can call another service by name (
my-service) instead of by IP. We'll see this clearly in Article 5. - storage-provisioner — a minikube addon that automatically provisions disk when you ask for it (Article 8).
Since minikube is single-node, that node is both the control plane and where workloads run. A production cluster keeps them separate: control plane nodes don't run user applications. But the components' roles are identical.
How a request travels through the system
Let's tie it together with an example — when you say "run 3 copies of the application":
1. kubectl sends the YAML up ──► kube-apiserver
2. apiserver writes "want 3 copies" ──► etcd
3. controller-manager sees: want 3, have 0 ──► creates 3 pods (written via apiserver)
4. scheduler sees 3 pods with no node ──► assigns each pod to a node
5. kubelet on that node asks apiserver "any pods of mine?" ──► starts the containers
6. kube-proxy updates the network rules so they're reachable
No component "commands" another directly. They all read/write state through the API server and react — a loosely coupled but resilient architecture. This is also why Kubernetes self-heals well: each controller quietly pulls its own piece of work back to the desired state.
Wrap-up
A Kubernetes cluster consists of a control plane (the brain) and nodes (the muscle). The control plane has kube-apiserver (the single gateway, everything goes through it), etcd (stores all state), the scheduler (picks a node for the pod) and the controller-manager (runs control loops to keep desired state). Each node has kubelet (runs & reports pods), kube-proxy (networking for Services) and a container runtime. In minikube, these very components run as pods in kube-system — we can see them with our own eyes. The point to burn into memory: every interaction goes through the API server, and the system operates through state-reconciliation loops.
Enough theory. In Article 2 we install minikube + kubectl properly and run our first commands on a cluster of our own.