flowchart TB
K["kubectl / client"] --> API["kube-apiserver"]
API <--> E[("etcd")]
S["kube-scheduler"] <--> API
CM["kube-controller-manager"] <--> API
CCM["cloud-controller-manager"] <--> API
API <--> KL["kubelet on the nodes"]
| Component | Role |
|---|---|
| kube-apiserver | The only REST API into the control plane. Every client and component goes through it; it handles authentication, authorization, validation and admission control |
| etcd | A consistent key-value store holding all cluster state; uses Raft between members. Only the apiserver talks to etcd directly |
| kube-scheduler | Picks a node for new pods without one, based on resource requests, constraints, affinity… It only assigns the node; the kubelet on that node runs the containers |
| kube-controller-manager | Runs the control loops (Deployment, ReplicaSet, Node, Job…), watches state through the apiserver and fixes drift |
| cloud-controller-manager | Cloud-specific integration: nodes, routes, Services of type LoadBalancer |
On a kubeadm cluster these components run as static pods in the kube-system namespace. On EKS/GKE/AKS the provider manages them and they are not visible.
A Pending pod with the event 0/3 nodes are available: 3 Insufficient cpu is the scheduler talking: no node has enough CPU for the request.
kubectl get componentstatuses has been deprecated since Kubernetes 1.19; look at the pods in kube-system or the apiserver /readyz endpoint instead.
| Command | Meaning |
|---|---|
kubectl cluster-info |
Address of the apiserver and core services |
kubectl get pods -n kube-system |
System pods: apiserver, etcd, scheduler, CoreDNS… |
The path of an API request
kubectl apply → authentication → authorization (RBAC) → mutating admission
→ schema validation → validating admission → stored in etcd → watchers notified
Components never call each other directly. The scheduler, controllers, and kubelets watch the apiserver for changes and react, which is why the system keeps working even if one component restarts: it simply resumes watching.
How the scheduler decides
Scheduling has two phases. Filtering removes nodes that cannot run the pod (not enough CPU or memory, taints without a matching toleration, a nodeSelector that does not match). Scoring ranks the remaining nodes, for example preferring spread across zones or nodes that already have the image. The best-scoring node is written into the pod's spec.nodeName.
High availability
A production control plane runs three (or five) apiservers behind a load balancer and an etcd cluster with an odd number of members, so it survives a failure. The scheduler and controller-manager run several copies, but only one is active at a time thanks to leader election.
Protecting etcd
etcd holds the entire cluster state, including Secrets. On self-managed clusters, back it up regularly:
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-2026-01-15.db \
--endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key
Encrypting Secrets at rest in etcd is a separate setting worth enabling.
Ways to run a cluster
| Option | Use |
|---|---|
| kind, minikube, k3d | Local learning on a laptop |
| kubeadm | Building a standard cluster yourself on VMs |
| k3s | Lightweight distribution for edge devices and small servers |
| EKS, AKS, GKE | Managed control plane in the cloud |
Components follow a version skew policy: kubelets may lag the apiserver by a few minor versions but must never be newer, so upgrade the control plane first.