A Kubernetes cluster is split into two roles. The control plane stores the desired state of everything in the cluster and makes decisions about it. The worker nodes actually run your containers. Almost every CKA troubleshooting task comes down to knowing which component owns which job, so it is worth learning this map before anything else.
The kube-apiserver is the front door. Every client, from kubectl to the scheduler to the kubelet on each node, talks to the cluster only through the API server over HTTPS (on a kubeadm cluster, port 6443). The API server authenticates the caller, checks authorization (usually RBAC, role-based access control), runs admission controllers that can reject or modify a request, and then persists the object. It is the only component that talks to etcd directly.
etcd is a distributed, strongly consistent key-value store that holds all cluster state: every Pod, Service, Secret and ConfigMap. If etcd is lost and you have no backup, the cluster's configuration is gone even if the containers keep running for a while. That is why etcd backup is its own exam objective. etcd serves clients on port 2379 and talks to its peers on 2380.
The kube-scheduler watches for Pods that have no node assigned. For each one it filters out nodes that cannot run it (not enough CPU, a taint the Pod does not tolerate, an affinity rule that does not match) and then scores the rest, finally writing the chosen node name into the Pod's spec.nodeName. The scheduler does not start containers; it only makes the placement decision.
The kube-controller-manager runs many control loops in one process: the ReplicaSet controller, Deployment controller, Node controller, Job controller, EndpointSlice controller, ServiceAccount controller and others. Each loop compares desired state with actual state and acts to close the gap. If this component is down, new Pods are not created for Deployments, but existing Pods keep running.
On every node, the kubelet is the agent that makes the node's share of desired state real. It watches the API server for Pods bound to its node, asks the container runtime to pull images and start containers, runs probes and reports Pod and node status back. The kubelet is a systemd service, not a Pod, so you inspect it with systemctl status kubelet and journalctl -u kubelet. The container runtime (containerd or CRI-O) does the low-level work of creating containers, and the kubelet talks to it over the Container Runtime Interface (CRI).
kube-proxy runs on each node (usually as a DaemonSet) and programs packet-forwarding rules so that traffic sent to a Service's virtual IP reaches one of the Service's backing Pods. On a kubeadm cluster, the API server, etcd, scheduler and controller-manager run as static Pods in the kube-system namespace, which you can see with kubectl get pods -n kube-system.
Key terms
- kube-apiserver
- The central REST API for the cluster; the only component that reads and writes etcd, and the one every other component talks to.
- etcd
- A consistent, distributed key-value store holding all cluster state.
- kube-scheduler
- Assigns unscheduled Pods to nodes by filtering and scoring candidate nodes.
- kube-controller-manager
- A single binary running many reconciliation loops such as the ReplicaSet, Node and Job controllers.
- kubelet
- The node agent, run by systemd, that starts Pods via the container runtime and reports status.
- kube-proxy
- The per-node component that programs Service virtual IP forwarding rules.
A learner scales a Deployment from 2 to 5 replicas and nothing happens: the ReplicaSet still shows 2. kubectl get pods -n kube-system shows the kube-controller-manager Pod in CrashLoopBackOff because of a typo in its static Pod manifest. Fixing the manifest brings the controller back and the three new Pods appear within seconds.
Check yourself
Which component is the only one that talks directly to etcd?
The kube-apiserver. All other components read and write cluster state through the API server.
Why can't you see the kubelet with kubectl get pods -n kube-system?
The kubelet runs as a systemd service on the host, not as a Pod, so you check it with systemctl and journalctl.
If the scheduler is stopped, what happens to a newly created Deployment's Pods?
The ReplicaSet controller still creates the Pod objects, but they stay Pending because nothing assigns them a node.