1.3 Control Plane Components: API Server, etcd, Scheduler, Controller Manager
Right, let’s get under the hood. The “Control Plane” sounds like something from a sci-fi movie, but it’s really just the collection of brains that make your cluster more than a pile of expensive, blinking hardware. It’s the set of services that take your politely worded YAML manifest (kubectl apply -f please.yaml), decide it’s actually a command, and then tirelessly works to make reality match your desired state. If it fails, it will try again. And again. And again. It’s the most persistent, pedantic, and powerful system administrator you’ve ever met.
The control plane isn’t a single monolithic application; it’s a set of highly specialized components. In a production cluster, these typically run across multiple machines for redundancy, but for learning, we often squish them all onto one node, which we charmingly call a “single-node control plane.” Don’t let the name fool you; it’s still running all the same components.
The Bouncer: kube-apiserver
This is it. The grand central station of your entire cluster. Every single communication, whether it’s from a human (kubectl), another control plane component, or a node agent (kubelet), goes through the API Server. It doesn’t actually do things itself; it’s a validation and routing machine. You hand it a manifest, and its job is to:
- Authenticate you: Who are you?
- Authorize you: Are you allowed to do this?
- Validate your YAML/JSON: Does this make even a shred of sense? Did you forget a
namefield? It will absolutely reject it. This is your first line of defense against typos. - Persist the state: It writes the desired state of your object (e.g., a Pod) to etcd.
- Notify watchers: It tells all the other components that care, “Hey, someone just created a new Pod object!”
You interact with it directly all the time. kubectl is just a fancy HTTP client that talks to the API Server. You can even use curl if you’re a masochist and handle the TLS and authentication yourself.
# This is essentially what kubectl is doing for you behind the scenes.
# First, get a token (this is a simplified example, ways to auth vary)
TOKEN=$(cat /path/to/serviceaccount/token)
# Then, curl the API server directly to list pods
curl -X GET https://your-api-server:6443/api/v1/namespaces/default/pods \
--header "Authorization: Bearer $TOKEN" \
--insecure # Don't do this in prod, we're just skipping cert verification for the example
The Single Source of Truth: etcd
If the API Server is the bouncer, etcd is the sacred, highly consistent ledger it guards. This is a distributed, reliable key-value store where the entire declared state of your cluster lives. Not the actual state of running processes, but the state you asked for. “I want 3 replicas of nginx.” That goes in etcd.
The API Server is the only component that talks to etcd directly. This is a brilliant design decision. It means every other system gets a simplified, validated view of the world through the API, and etcd isn’t bombarded by every component. It’s the cluster’s brain, and it’s designed for consistency and speed above all else. If you lose etcd, your cluster loses its mind. It forgets everything you ever told it. You back this thing up religiously. No jokes here.
The Matchmaker: kube-scheduler
The scheduler is brutally simple in its mission: it finds a spec (a Pod that has no nodeName) and finds a node for it. It’s a matchmaking service for Pods and Nodes.
It doesn’t just pick a node at random. It runs a two-step process:
- Filtering: “Which nodes can run this Pod?” This filters out nodes that don’t have enough CPU/RAM, don’t have the requested port available, don’t match the node selector/affinity rules, or haven’t passed their health checks.
- Scoring: “Which of these eligible nodes is the best fit?” It scores the remaining nodes based on things like spreading Pods across nodes for high availability, prioritizing nodes that already have the desired container image, and balancing resource usage.
You can see its logic at work. Create a Pod that requests 4 CPUs and watch it get stuck in Pending if no node in your cluster has that capacity free.
# pod-too-big.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-massive-pod
spec:
containers:
- name: stress-test
image: busybox
command: ["sleep", "3600"]
resources:
requests:
memory: "64Gi" # An absurdly large request
cpu: "16" # Likewise absurd
Apply this, then run kubectl describe pod my-massive-pod. The Events section will show the scheduler frankly telling you it can’t find a node that fits. This isn’t an error; it’s the scheduler working correctly.
The Infinite Loop: kube-controller-manager
This is where the magic of “desired state” really happens. The controller manager isn’t one thing; it’s a collection of loops that constantly watch the state of the cluster through the API Server and try to nudge reality toward the desired state stored in etcd.
Think of it as a collection of obsessive-compulsive robots. The “ReplicationSet controller” robot wakes up every few seconds, checks how many Pods are running for a given ReplicaSet, and if it finds 2 when there should be 3, it freaks out and tells the API Server to create a new Pod. Then the scheduler assigns it, and the kubelet runs it. Another robot handles Nodes. When you add a new node to the cluster, the Node controller is the one that marks it as Ready. Another handles service accounts, another endpoints… you get the idea.
They are relentlessly vigilant. You kubectl delete pod a Pod managed by a ReplicaSet? The controller notices it’s gone and replaces it before you can even blink. This is the core of Kubernetes’ self-healing capability. It’s not psychic; it’s just a bunch of loops asking the API Server “is everything okay? …how about now?” over and over.
The Pitfall: This eventual consistency model can confuse newcomers. You change a field in a Deployment? The controller manager loop sees the change and initiates a rolling update. It takes a moment. It’s not instantaneous. You have to learn to think asynchronously. You shout your request into the API Server and then trust the various controllers to carry it out. It feels weird until it doesn’t, and then it feels brilliant.