home / writing / inside-a-kubernetes-cluster

What actually happens inside a Kubernetes cluster

Kubernetes looks like a pile of YAML until you know who reads it. This guide follows one request through the cluster and then covers the objects that keep workloads healthy.

The control plane and node components

ComponentWhereJob
kube-apiserverControl planeThe front door. Every read and write goes through it, including from other components.
etcdControl planeA key-value store holding the cluster's desired and current state. The only stateful core piece.
kube-schedulerControl planePicks a node for each new pod based on requests, constraints and available resources.
controller managerControl planeRuns the control loops (see below).
kubeletEvery nodeAgent that makes the containers for assigned pods actually run, and reports their health.
kube-proxyEvery nodePrograms the node's networking rules so Service addresses reach the right pods.
container runtimeEvery nodePulls images and runs containers, for example containerd or CRI-O.

The controller manager

A controller is a loop that compares the desired state you declared with the current state it observes, then acts to close the gap. This is the heart of Kubernetes. The controller manager bundles many of them, including:

  • Node controller: notices when nodes become unreachable and reacts.
  • ReplicaSet controller: keeps the requested number of pod replicas running.
  • Endpoints controller: keeps each Service's list of backing pods up to date.
  • Service account and token controllers: create default accounts and credentials for pods.
  • Namespace controller: cleans up everything inside a namespace when it is deleted.

Following one kubectl apply

  1. kubectl apply -f deploy.yaml sends the object to the API server, which authenticates you, checks you are authorised, runs admission checks and validates it.
  2. The API server stores the Deployment in etcd.
  3. The Deployment controller creates a ReplicaSet, and the ReplicaSet controller creates Pod objects. They have no node yet.
  4. The scheduler sees unscheduled pods and binds each one to a node.
  5. The kubelet on that node sees a pod assigned to it, asks the runtime to pull the image and start the containers, then reports status back.
  6. The Endpoints controller adds the pod to any matching Service once it is ready.

No component calls another directly to say "do this". Each one watches the API server and reacts to changes. That is why the system recovers by itself when something dies partway through.

Container runtimes and the CRI

Early on, Kubernetes talked straight to Docker. To support other runtimes it introduced the Container Runtime Interface (CRI): any runtime that implements it can be plugged in, and the image and runtime formats follow the OCI specifications. Docker Engine predates the CRI and does not implement it, so Kubernetes shipped a small adapter called dockershim. That adapter was removed in Kubernetes 1.24. Docker-built images still run fine, because they are OCI images, but the node now needs containerd or CRI-O. The node-side debugging tool is crictl, not docker.

Requests, limits and quotas

Every container can declare how much CPU and memory it requests (what the scheduler reserves) and its limit (the ceiling). Exceed a CPU limit and you are throttled. Exceed a memory limit and the container is killed.

resources:
  requests: { cpu: "250m", memory: "256Mi" }
  limits:   { memory: "512Mi" }
  • A LimitRange sets default and maximum requests and limits per container in a namespace.
  • A ResourceQuota caps the total a namespace can consume, including object counts.

Readiness and liveness probes

  • Readiness answers "should this pod receive traffic yet?" A failing pod is removed from Service endpoints but not restarted. Use it for warm-up and for temporary overload.
  • Liveness answers "is this container stuck for good?" A failing one is restarted. Use it sparingly, and never on something that depends on a downstream service, or an outage there will restart every pod.

Rollout strategies

  • Rolling update (default): replace pods gradually, controlled by maxSurge and maxUnavailable.
  • Blue/green: run the new version beside the old one, then switch the Service selector in one step. Instant rollback, at the cost of double capacity.
  • Canary: send a small share of traffic to the new version first and widen it as metrics stay healthy. Tools such as Argo Rollouts automate this.

Admission control and extending the API

After a request is authenticated and authorised, admission controllers can change or reject it. A mutating webhook can modify the object, for example injecting a sidecar or default labels. A validating webhook can only accept or reject, which is how policy engines enforce rules such as "no privileged pods".

You can also add your own resource types with a CustomResourceDefinition (CRD), and then write a custom controller that watches those objects and acts on them. This is the operator pattern, and it is how most Kubernetes add-ons work.