KCNA — Kubernetes and Cloud Native Associate
Why the Control Plane Is Split This Way
One-line summary
Kubernetes is not a "system that executes commands" but "a system in which you write down the desired state and controllers bring reality into line with it." The control plane has several pieces because the actors that run this loop were divided by role.
Why this was needed
An imperative system executes "start 3 Pods" and is done. But what if a node dies? Nobody cares, because the command has already finished.
A declarative system stores "I want a state with 3 Pods." Then someone keeps reading the current state, compares it with the desired state, and narrows the difference if they differ. This loop is called the reconciliation loop, and it is the whole of Kubernetes. Everything else is machinery to make this loop safe and scalable.
Seen this way, the separation of components reads naturally. Where do we write the state (etcd)? Who lets others read and write that state (kube-apiserver)? Who runs the loops (kube-controller-manager)? Who runs the special loop that decides which node a Pod goes on (kube-scheduler)? And who actually starts the containers on the node (kubelet)?
How it works
The control plane
| Component | What it does | If it disappears |
|---|---|---|
| etcd | The only store holding all of the cluster's state | The cluster's memory is gone |
| kube-apiserver | The only door to etcd. Authentication, authorization, admission, validation | Nobody can read or write anything |
| kube-controller-manager | Dozens of controller loops such as Deployment/ReplicaSet/Node/Endpoint | Declarations are stored but nothing happens |
| kube-scheduler | Assigns a node to Pending Pods | Pods are created but stay Pending forever |
No component touches etcd directly. The scheduler, the controller manager, and kubelet all go through the apiserver. That way authentication, authorization, admission, and audit logging are applied in one place. This is the starting point of the security design that leads into KCSA.
It is also good to know the key structure inside etcd. All resources live under /registry/, namespaced resources take the form /registry/<종류>/<네임스페이스>/<이름> (kind, namespace, name), and cluster-scoped resources take the form /registry/<종류>/<이름> (kind, name). Values are serialized as protobuf by default.
Nodes
- kubelet: The node's agent. It watches the apiserver, and when it sees a Pod assigned to its own node, it tells the runtime to run it through the CRI.
- kube-proxy: Writes the rules onto the node that forward a Service's virtual IP to actual Pod IPs. (If something like Cilium takes over this role with eBPF, you may not install kube-proxy at all.)
- Container runtime: containerd and the like.
The API is made of resources
There is only one way to talk to Kubernetes: CRUD on REST resources. Creating a Deployment and deleting a Pod use exactly the same grammar. With kubectl api-resources you can see the full list of resources this cluster knows, and with kubectl explain you can see what each field means. The habit of asking the cluster directly without opening a documentation site is the fastest, both in the exam room and on the job.
Label selectors: the glue of loose coupling
Kubernetes has almost no direct references like "this Service points to those 3 Pods." Instead you attach labels and pick with selectors. A Service, a ReplicaSet, and a NetworkPolicy all find their targets by selector. That is why a single typo in a selector creates a silent outage: the object is created normally, but it just catches nothing.
What it looks like in practice
This really happened in the author's homelab. One day the cluster did not respond, and dial tcp 10.0.0.111:6443: connect: no route to host appeared. The cause was DHCP: the control plane node's IP had been refreshed from .111 to .120.
Here the separation of components showed up in a visible form. etcd and kube-apiserver tried to bind to the nonexistent address .111, failed, and fell into CrashLoopBackOff, but kube-scheduler and controller-manager bind to 127.0.0.1, so their processes were perfectly alive. They were alive but could do nothing, because without the apiserver the controllers have nothing to read or write.
The decisive evidence was in the certificate. The Subject Alternative Name of apiserver.crt did not include .120. So changing only the IP does not recover things: connecting to an address that is not in the SAN fails TLS verification.
When the same cluster was later expanded to 7 nodes (3 control plane + 4 GPU workers), an even more painful lesson came out. Even though the etcd members were made 3 to have a quorum, controlPlaneEndpoint was hard-coded not to a VIP or DNS but to cp-1's physical IP (10.0.0.120:6443). If cp-1 dies, the etcd quorum is fine at 2/3 and the apiserver processes on the other two nodes are healthy, but kubectl and all 7 kubelets lose access. It is a state where "the control plane is alive but nobody can find the door." Data availability and access availability are entirely separate problems: that is the summary of this incident.
What you will do in the next lab
In the lab right after this, you create the kcna-arch namespace, extract the node list, and ask the cluster about its API directly with kubectl api-resources and kubectl explain. You pick Pods with label selectors, and at the end you create the same Deployment in two ways, imperative and declarative, and check what differs.