Architecture#
A Kubernetes cluster has two planes. The control plane holds the
desired state, schedules work, and reconciles reality against the
declaration. The data plane is the pool of worker nodes that run
the actual pods. Every cluster, from a laptop kind cluster to a
hyperscaler-managed regional fleet, has the same components doing
the same jobs; only the deployment shape and the operator’s view
into them change.
flowchart TB
subgraph CP[Control plane]
direction TB
API[kube-apiserver]
ETCD[(etcd)]
SCHED[kube-scheduler]
CM[kube-controller-manager]
CCM[cloud-controller-manager]
API --- ETCD
API --- SCHED
API --- CM
API --- CCM
end
subgraph N1[Worker node 1]
K1[kubelet]
P1[kube-proxy]
R1["CRI runtime (containerd)"]
K1 --- R1
end
subgraph N2[Worker node 2]
K2[kubelet]
P2[kube-proxy]
R2["CRI runtime (containerd)"]
K2 --- R2
end
CLI[kubectl / client] -->|HTTPS| API
API -->|watch / exec| K1
API -->|watch / exec| K2
CCM -->|provider API| CLOUD[("cloud or vCenter API")]
The whole control plane talks through the API server. No component reads or writes etcd directly except the API server. No component talks to nodes directly except the API server. This single choke point is what makes the cluster auditable and what makes API server availability the binding constraint for the entire control plane.
The control plane#
Five processes (four mandatory plus the optional cloud-controller- manager) make up the control plane. On a self-managed cluster they run on dedicated control-plane nodes; on a managed cluster (EKS, GKE, AKS, TKG) the provider hides them behind their own SRE team.
kube-apiserver#
The stateless REST front end for the cluster. Every read, every write, every watch streams through it. It validates requests against schemas, runs admission controllers, persists accepted state to etcd, and serves watch streams to the controllers and kubelets that subscribe.
Property |
Detail |
|---|---|
Port |
|
Auth |
X.509 client certs, bearer tokens, service-account JWTs, OIDC, webhook. Authentication is pluggable. |
Authz |
RBAC (default), ABAC, Node, webhook. RBAC is what the operator writes against. |
Admission |
Mutating then validating admission plugins (PodSecurity, ResourceQuota, LimitRanger, ImagePolicyWebhook) run on every write. |
Storage |
All persisted state in etcd, keyed by resource path ( |
Scaling |
Stateless. Add replicas behind a load balancer for HA; HA needs an HA etcd quorum to be useful. |
The API server is the audit log. Enable structured audit policy
(--audit-policy-file) and ship the log; everything the cluster
ever did flows through this one process.
etcd#
A distributed key-value store using the Raft consensus algorithm. Kubernetes stores every object here as protobuf-encoded JSON keyed by resource path. Cluster state, secrets, RBAC, configmaps, service account tokens, every CRD instance, all of it.
Property |
Detail |
|---|---|
Port |
|
Quorum |
3 or 5 voting members; odd numbers tolerate the most failures (3 tolerates 1, 5 tolerates 2). |
Auth |
Mutual TLS between every client and peer. API server is the only client most of the time. |
Backup |
|
Encryption at rest |
Off by default. Enable via |
Performance |
Latency-sensitive. SSDs, low-latency disks, dedicated network if possible. |
Losing etcd quorum is a cluster outage. Losing all etcd state without a backup is a cluster rebuild. The operator’s first disaster-recovery drill is restoring from a snapshot.
kube-scheduler#
A loop that watches for pods with an empty spec.nodeName and
binds each one to a node. Two phases:
Filtering, drop nodes that fail hard constraints (taints, node selectors, affinity, resource requests, port conflicts, topology spread).
Scoring, rank the survivors by soft preferences (least requested, image locality, inter-pod affinity, topology spread) and bind to the top.
Property |
Detail |
|---|---|
Pluggability |
Scheduling framework lets the operator add custom plugins or run a second scheduler in parallel ( |
Preemption |
High-priority pods can evict lower-priority pods to make room. Driven by |
Failure mode |
If the scheduler is down, no new pods get placed. Running pods are unaffected; the cluster degrades only on the new-work axis. |
Custom scheduling decisions (GPU-aware bin packing, locality to data, batch gang scheduling) are common reasons the operator writes plugins or runs a sidecar scheduler.
kube-controller-manager#
A single binary that hosts dozens of independent control loops, each watching one or more resource types and reconciling state. Examples worth knowing:
Controller |
Job |
|---|---|
Deployment controller |
Creates / updates ReplicaSets when a Deployment changes. |
ReplicaSet controller |
Maintains the desired pod count for a ReplicaSet. |
StatefulSet controller |
Manages stable identities and ordered rollout for stateful workloads. |
DaemonSet controller |
Creates one pod per node matching the selector. |
Job / CronJob controllers |
Run-to-completion and scheduled work. |
Node controller |
Marks nodes unhealthy when the kubelet stops heartbeating. |
Service controller |
Allocates ClusterIPs and updates Endpoints / EndpointSlices. |
Endpoint(Slice) controller |
Tracks which pods back which Service. |
PV / PVC controllers |
Binds claims to volumes; provisions dynamically through a StorageClass. |
Service account / token controller |
Creates default service accounts and bound tokens. |
Namespace controller |
Drives namespace termination through finalizers. |
Every controller follows the same pattern, watch the API for changes, compute desired state, write back the difference. The operator writes custom controllers in the same shape when extending the cluster with operators and CRDs.
cloud-controller-manager#
The piece that knows about the underlying infrastructure. Splits out of kube-controller-manager so a managed cluster’s provider ships their own without forking core Kubernetes. Responsible for:
Node controller (cloud variant), tags nodes with provider zone, region, instance type; reacts when an instance disappears.
Route controller, programs the underlying network’s route tables when nodes need pod-CIDR routes.
Service controller, creates and tears down the cloud load balancer behind a
type: LoadBalancerService (AWS ELB / NLB, GCP Cloud Load Balancing, Azure Load Balancer, NSX Advanced LB on vSphere with Tanzu).
On AWS it talks to EC2 and ELB APIs; on GCP, Compute and LB; on Azure, the Azure Resource Manager; on VMware Tanzu Kubernetes Grid, the vCenter API plus NSX. Kubeadm clusters with no cloud integration ship without this binary.
The data plane#
Every worker node runs three components plus whatever DaemonSet pods land there (log shippers, node exporters, CSI drivers).
kubelet#
The node agent. Subscribes to the API server for pods bound to its
own nodeName, talks to the local container runtime to bring
them up, runs probes, reports status back. The kubelet is the
single point of trust between the control plane and the node.
Property |
Detail |
|---|---|
Port |
|
Authentication |
Node-scoped X.509 client cert; rotated via certificate signing requests when |
Authorization |
Defaults to the |
Runtime interface |
Container Runtime Interface (CRI) over gRPC on a Unix socket ( |
Storage and network |
Drives CSI plugins for volume mounts and CNI plugins for pod network setup. |
Probes |
Runs liveness, readiness, and startup probes; restarts containers and toggles endpoint membership accordingly. |
Eviction |
Watches node-level pressure (memory, disk, PID) and evicts pods to keep the node healthy. Tunable via |
If the kubelet stops heartbeating (Node.status not updated
within the configured grace period) the node controller marks the
node NotReady and, eventually, evicts its pods to other nodes.
kube-proxy#
The per-node implementation of Service. Watches Endpoints / EndpointSlices and programs a load-balanced virtual IP for each ClusterIP. Three modes:
Mode |
Behavior |
|---|---|
|
Programs DNAT rules that match the ClusterIP and rewrite to a randomly chosen endpoint pod. Scales to a few thousand services before rule evaluation cost shows up. |
|
Programs Linux IPVS rules; better scale, hash-based selection, supports more LB algorithms (round-robin, least conn, source hash). |
|
Newer alternative on top of nftables; replaces iptables on modern distros. |
eBPF-based dataplanes (Cilium, Calico-eBPF) replace kube-proxy entirely with eBPF programs attached to the pod network, lower latency and richer policy.
Container runtime#
The component that actually pulls images and runs containers. The kubelet talks CRI (gRPC) to whichever runtime is installed.
Runtime |
Detail |
|---|---|
|
The current default. CNCF graduate, derived from Docker. Most distros ship this. |
|
Red Hat / OpenShift default. Minimal, OCI-focused. |
|
Shim that lets the old Docker engine satisfy CRI. Used where Docker is still mandated. |
|
Sandboxed runtimes. Run a stripped kernel (gVisor) or a microVM (Kata) per pod, trading performance for stronger isolation. |
The container runtime is what the operator’s threat model lives in on the data plane. A container escape is a runtime escape; pick the runtime accordingly when the workload is hostile.
Cluster addons#
A working cluster needs more than the binaries above. The
following addons are present in virtually every production cluster
and are usually installed as DaemonSets or Deployments in
kube-system.
CoreDNS#
Cluster DNS. Resolves <service>.<namespace>.svc.cluster.local
into ClusterIPs, plus pod DNS, headless service A records, and
external forwarding. Sits behind a Service of its own that every
pod’s /etc/resolv.conf points at via the kubelet’s pod-DNS
config.
CNI plugin#
The network plugin that wires up pod-to-pod connectivity. The kubelet calls a CNI binary when a pod starts to set up its network namespace, allocate an IP from the cluster CIDR, and program whatever overlay or routing the plugin needs. Choices:
Plugin |
Detail |
|---|---|
Calico |
BGP routing or VXLAN overlay; NetworkPolicy support; eBPF dataplane available. |
Cilium |
eBPF-native. Pod networking, NetworkPolicy, service mesh, observability (Hubble), kube-proxy replacement. |
Flannel |
Simple VXLAN overlay; no policy support out of the box. |
Weave Net |
Mesh VXLAN; lightweight; policy support. |
AWS VPC CNI / Azure CNI / GCP NetD |
Provider-native plugins that assign pods real cloud-VPC IPs (no overlay), so cloud security groups apply directly. |
VMware NSX |
NSX-T integration on Tanzu Kubernetes Grid. Pod networks become NSX segments. |
The CNI choice constrains NetworkPolicy enforcement, mTLS support, and the operator’s visibility into east-west traffic.
CSI plugin#
The storage equivalent of CNI. A CSI driver implements three gRPC services (controller, node, identity) so kubelets can mount cloud disks, NFS shares, vSAN volumes, or any storage backend a vendor ships a driver for. Triggered by the PV / PVC controllers when a claim binds.
Metrics server#
A small aggregator that scrapes kubelet.metrics from every node
and exposes the data through the Metrics API
(metrics.k8s.io). Required for kubectl top and for the
Horizontal Pod Autoscaler’s CPU / memory rules. Not a long-term
metrics store; pair with Prometheus for that.
Ingress controller#
The data-plane piece behind an Ingress or Gateway resource. Common choices: ingress-nginx, Traefik, HAProxy Ingress, Contour, NSX Advanced LB (Avi) on Tanzu, plus the managed AWS / GCP / Azure ingress controllers fronted by their cloud load balancers. The controller watches Ingress / HTTPRoute / Gateway objects and programs its own dataplane (an nginx, a sidecar Envoy, a cloud LB) to match.
Request flow#
A kubectl apply -f deploy.yaml traverses every component above.
sequenceDiagram
participant U as kubectl
participant API as kube-apiserver
participant ETCD as etcd
participant DC as Deployment ctrl
participant RSC as ReplicaSet ctrl
participant SCH as kube-scheduler
participant KL as kubelet
participant CRI as CRI runtime
U->>API: PUT /apis/apps/v1/.../deployments
API->>API: auth, admission, validate
API->>ETCD: write Deployment object
ETCD-->>API: ack
API-->>U: 200 OK
DC->>API: watch Deployments
DC->>API: create ReplicaSet
RSC->>API: watch ReplicaSets
RSC->>API: create N Pods
SCH->>API: watch unscheduled Pods
SCH->>API: bind Pod to Node
KL->>API: watch Pods for myNode
KL->>CRI: pull image, create container
CRI-->>KL: container running
KL->>API: update Pod status
Every arrow above is a watch or write against the API server. No shortcut paths, no direct etcd reads, no node-to-node coordination. This is what makes the cluster legible and the API server the choke point.
High availability#
A production control plane runs every binary above with redundancy.
etcd, a quorum of 3 or 5 across availability zones. Backups off-cluster, encryption at rest enabled.
kube-apiserver, two or more replicas behind an L4 load balancer. Stateless so the LB is sufficient.
kube-scheduler and kube-controller-manager, leader- elected; run two replicas, only one is active at a time.
cloud-controller-manager, same leader-election shape on clusters that have one.
Worker nodes, spread across zones;
topologySpreadConstraintson workloads to enforce the spread.
Managed clusters (EKS, GKE, AKS, TKG) handle this layer for the operator. The operator’s HA burden on a managed cluster is the worker pool and the workloads on it.