Kubernetes cluster architecture
You know the objects now: Pod, ReplicaSet, Deployment and Service. This chapter shows the machinery that makes them work. A cluster is a group of machines that work together to run your applications. Inside it there are two kinds of node: the control plane, which decides, and worker nodes, which run your containers. Everything you write is an API object that describes the state you want.
Kubernetes itselfwhat you work withwhat it is made oflit up in the walk-through
The map
Click a box to see what it does. Click it again to fold or unfold what is inside. With the keyboard, use the arrow keys to move and Enter to fold.
Text version of the map
- Kubernetes — keeps your containers running the way you declared. You write down the state you want; Kubernetes keeps comparing it with what is actually running and fixes the difference, forever.
kubectl version- Cluster — the set of machines (nodes) that Kubernetes manages as one computer. You never pick a machine for your app; you hand the app to the cluster.
kubectl cluster-info- Control Plane — the brain. It stores the desired state, decides where things run and notices when reality drifts. In production it runs on its own machines and does not run your apps.
kubectl get pods -n kube-system- API Server — the front door. Every
kubectlcommand and every other component talks only to it. It checks who you are, validates the object and saves it. Nothing else talks to etcd.kubectl api-resources - Scheduler — finds Pods with no node yet and picks one for each, based on free CPU and memory, node labels, affinity and taints. It only decides; the kubelet does the starting.
kubectl get events --field-selector reason=Scheduled - Controller Manager — runs the control loops: observe, compare with the desired state, act. The Deployment, ReplicaSet, Node and Job controllers all live here. This is what makes Kubernetes self-healing.
kubectl get pods -n kube-system -l component=kube-controller-manager - Cloud-Controller-Manager — the loops that talk to your cloud provider: create a load balancer for a Service, notice a deleted VM, set up routes. Local clusters such as kind and minikube do not have one.
- etcd — a consistent key-value store and the cluster's only source of truth. Every object you create ends up here. Lose etcd without a backup and you lose the cluster's state.
kubectl get --raw /livez/etcd
- API Server — the front door. Every
- Worker Node — a machine (VM or bare metal) that runs your Pods. Add more worker nodes and the cluster gets more room.
kubectl get nodes -o wide- kubelet — the agent on every node. It watches the API server for Pods assigned to its node, asks the container runtime to start them, runs their health probes and reports status back.
kubectl describe node <node-name> - Kube-Proxy — writes the network rules (iptables, IPVS or nftables) on each node so that traffic sent to a Service IP lands on one of its Pods.
kubectl get pods -n kube-system -l k8s-app=kube-proxy - Container Runtime — pulls images and runs containers, usually containerd or CRI-O, through the Container Runtime Interface. Since Kubernetes 1.24 the kubelet does not talk to Docker Engine directly, but images you build with Docker run fine.
kubectl get nodes -o wide # CONTAINER-RUNTIME column
- kubelet — the agent on every node. It watches the API server for Pods assigned to its node, asks the container runtime to start them, runs their health probes and reports status back.
- Control Plane — the brain. It stores the desired state, decides where things run and notices when reality drifts. In production it runs on its own machines and does not run your apps.
- Pod — the smallest thing Kubernetes runs: one or more containers that share one IP address and can share volumes. Pods are disposable; when one dies it is replaced, not repaired.
kubectl get pods -o wide- Container — your image, running. The same container you know from Docker. Containers in one Pod reach each other on
localhost.kubectl logs <pod> -c <container>
- Container — your image, running. The same container you know from Docker. Containers in one Pod reach each other on
- Service — a stable name and virtual IP in front of a changing set of Pods, chosen by label. Pods come and go with new IPs; the Service address stays the same.
kubectl get svc- Service Types — how far the Service is reachable. Each type builds on the one before it.
- ClusterIP — the default. A virtual IP reachable only from inside the cluster, plus a DNS name like
web.default.svc.cluster.local.kubectl expose deployment web --port=80 - NodePort — also opens the same port (30000–32767 by default) on every node, so
<any-node-ip>:<port>reaches the Service.kubectl expose deployment web --type=NodePort --port=80 - LoadBalancer — also asks the cloud for an external load balancer with a public address. The cloud-controller-manager creates it.
kubectl expose deployment web --type=LoadBalancer --port=80 - ExternalName — no Pods and no proxying: the Service name becomes a DNS alias (CNAME) for a name outside the cluster, such as a managed database.
kubectl create service externalname db --external-name=db.example.com
- ClusterIP — the default. A virtual IP reachable only from inside the cluster, plus a DNS name like
- Service Types — how far the Service is reachable. Each type builds on the one before it.
- Deployment — what you usually write for a stateless app: a Pod template plus how many copies you want. Changing the template triggers a rolling update.
kubectl rollout status deployment/web - ReplicaSet — keeps exactly N identical Pods running. A Deployment creates a new ReplicaSet for each version, which is how rollbacks work. You rarely write one yourself.
kubectl get rs - ConfigMap — plain configuration (URLs, flags, whole config files) kept outside the image and handed to Pods as environment variables or files.
kubectl create configmap app-config --from-literal=LOG_LEVEL=info - Secret — like a ConfigMap, for passwords and keys. The values are only base64-encoded, not encrypted, unless encryption at rest is turned on, so limit who can read them.
kubectl create secret generic db --from-literal=PASSWORD=change-me - Namespace — a folder for objects: names only have to be unique inside one, and quotas and access rules apply per namespace. It does not block network traffic by itself.
kubectl get namespaces
- Cluster — the set of machines (nodes) that Kubernetes manages as one computer. You never pick a machine for your app; you hand the app to the cluster.
Two kinds of node
| Control plane | Worker node | |
|---|---|---|
| Job | Decide and remember | Run containers |
| Runs | API server, scheduler, controller manager, cloud controller manager, etcd | kubelet, kube-proxy, container runtime, and your Pods |
| If it goes down | Running apps keep running, but nothing new is scheduled or healed | Its Pods are recreated on other nodes |
| How many | Usually 3 for high availability (etcd needs a majority) | As many as you need, from 1 to thousands |
Follow one kubectl apply
What happens between typing the command and a container running?
- You run
kubectl apply -f web.yaml. kubectl sends the Deployment to the API server, which checks who you are and whether the object is valid. - The API server saves the Deployment in etcd. At this point nothing is running. The cluster only knows what you want.
- Controllers react. The Deployment controller sees a Deployment without a ReplicaSet and creates one. The ReplicaSet controller sees 0 of 3 Pods and creates 3 Pod objects, still with no node.
- The scheduler places the Pods. It sees Pods with no node, scores the worker nodes, and writes the chosen node name into each Pod.
- The kubelet starts them. The kubelet on each chosen node sees a Pod assigned to it, tells the container runtime to pull the image and start the containers, then reports the Pod as Running.
- Traffic finds them. A Service whose selector matches the Pods' labels lists their IPs, and kube-proxy on every node updates its rules so the ClusterIP reaches them.
Every arrow in this story goes through the API server. The scheduler never calls the kubelet; it writes a field, and the kubelet notices.
The objects you write
A Deployment, a Service and a ConfigMap are enough to run most stateless apps:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3 # the ReplicaSet keeps 3 Pods alive
selector:
matchLabels: { app: web }
template: # the Pod template
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: nginx:1.27
ports: [{ containerPort: 80 }]
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP # the default
selector: { app: web } # matches the Pod labels above
ports: [{ port: 80, targetPort: 80 }]
The link between a Service and its Pods is only the label app: web. Get the label wrong and the Service has no endpoints, which is one of the most common "it does not work" bugs.
Try it yourself
You need Docker, kind and kubectl. Versions and names in the output will differ on your machine.
-
Step 1 · Create a cluster
kind runs each node as a Docker container. This cluster has a single node that is both control plane and worker.
$ kind create cluster --name lab $ kubectl get nodes NAME STATUS ROLES AGE VERSION lab-control-plane Ready control-plane 40s v1.31.0 -
Step 2 · Find the control plane
The components from the map are Pods in the
kube-systemnamespace. There is no cloud-controller-manager on kind.$ kubectl get pods -n kube-system NAME READY STATUS coredns-7c65d6cfc9-6bz8q 1/1 Running etcd-lab-control-plane 1/1 Running kube-apiserver-lab-control-plane 1/1 Running kube-controller-manager-lab-control-plane 1/1 Running kube-proxy-4x2mv 1/1 Running kube-scheduler-lab-control-plane 1/1 Running -
Step 3 · Deploy and look at the chain
$ kubectl create deployment web --image=nginx:1.27 --replicas=3 $ kubectl get deploy,rs,pods NAME READY UP-TO-DATE AVAILABLE deployment.apps/web 3/3 3 3 NAME DESIRED CURRENT READY replicaset.apps/web-6d4cf56db6 3 3 3 NAME READY STATUS pod/web-6d4cf56db6-8kq2p 1/1 Running pod/web-6d4cf56db6-m7x4t 1/1 Running pod/web-6d4cf56db6-zt9wn 1/1 RunningThe Pod names carry the ReplicaSet's name, which carries the Deployment's name.
-
Step 4 · Put a Service in front
$ kubectl expose deployment web --port=80 $ kubectl get endpointslices -l kubernetes.io/service-name=web NAME ADDRESSTYPE PORTS ENDPOINTS web-x7k2d IPv4 80 10.244.0.5,10.244.0.6,10.244.0.7 -
Step 5 · Watch it heal
Delete one Pod and watch the ReplicaSet create a replacement within seconds.
$ kubectl delete pod web-6d4cf56db6-8kq2p $ kubectl get pods NAME READY STATUS AGE web-6d4cf56db6-m7x4t 1/1 Running 3m web-6d4cf56db6-zt9wn 1/1 Running 3m web-6d4cf56db6-qr5vb 1/1 Running 4s $ kind delete cluster --name lab
Recap
- A cluster has two kinds of node: the control plane decides, worker nodes run Pods.
- The API server is the only door, and etcd is the only memory. Everything else watches the API server.
- The scheduler picks a node; the kubelet on that node starts the containers through the container runtime.
- You write objects (Deployment, Service, ConfigMap, Secret) that describe the desired state; controllers make it true.
- A Deployment manages ReplicaSets, a ReplicaSet manages Pods, a Pod holds containers, and a Service finds Pods by label.
Quick check
Show answer
The ReplicaSet controller (in the controller manager) sees 2 of 3 Pods and creates a new Pod object. The scheduler gives it a node. The kubelet on that node starts its containers through the container runtime. All three only talk to the API server.
Show answer
No. Running Pods keep running and kube-proxy rules stay in place. But nothing changes either: no new deploys, no scaling, and a crashed Pod on a dead node is not rescheduled until the control plane is back.
Kubernetes cluster architecture: common questions
What is the difference between the control plane and a worker node?
The control plane stores the desired state and decides where Pods run. Worker nodes run the Pods, using the kubelet, kube-proxy and a container runtime.
What does the kubelet do?
It is the agent on every node. It watches the API server for Pods assigned to its node, starts their containers through the container runtime and reports their status.