What Is Kubernetes? From 'Running Containers' to 'Declaring the State You Want'

· tech

#kubernetes#concept

📑 Contents

Many people find Kubernetes (K8s) hard because they’re buried from day one under kubectl, a pile of YAML fields, and dozens of resource names. But K8s really has one core idea; grasp it and everything after is a variation on the same sentence. This series starts from that idea — a declared desired state, plus a reconcile loop that keeps pulling reality towards it.

First ask: what problem does it actually solve

Say you already know Docker and have a containerised service. When you take it to Production you run into a pile of chores:

  • A container dies. Who restarts it automatically?
  • Traffic grows. Who opens more copies, and takes them back when traffic falls?
  • A whole machine dies. Where do the containers on it move to?
  • Shipping a new version: how do you roll it out without downtime, and roll back when it breaks?

Running docker run by hand one at a time, SSH-ing in to rescue things when they break — fine for a few machines, a disaster at a few dozen. K8s is the “container orchestrator” that looks after your containers — it automates “a pile of containers has to run on a pile of machines, stay alive, scale, and change versions”.

The core idea: declare the desired state, let it converge

But what’s really clever about K8s isn’t “lots of features”; it’s how it achieves them. You never issue step-by-step commands like “restart this container” or “start one on that machine”; you only declare the end state you want, and K8s works out how to get there — and keeps it there:

desired state you declare: replicas = 3 Controller control loop compare & correct actual state only 2 right now ① read ② act ③ observe 2 → create 1 → 3 ✓ reconcile loop: keep comparing desired with actual, fix the gap — this is the soul of K8s
You only declare "I want 3"; the Controller keeps watching the actual state and fills any gap it finds. One container dies, one gets replaced; a machine breaks, things start elsewhere — all of it falls out of this loop

This reconcile loop is the soul of all of K8s. Deployment, Service, every resource you’ll meet later — behind each is the same thing: you declare a desired state, and some controller keeps pulling reality towards it. Every post in this series comes back to that sentence.

Imperative vs declarative: why the difference matters

Another angle on the shift:

Imperative (the past)Declarative (K8s)
What you doIssue step-by-step commands: start this, stop thatDescribe the result you want: 3 copies, this version
Who maintains the stateYou (rescue it yourself when it breaks)The system (converges automatically, self-heals)
RepeatableHard (commands have order and side effects)Idempotent (apply as many times as you like, same result)
Version-controllableHardYes: one YAML file is your desired state

The biggest dividend of the declarative model is that your “desired state” becomes a file you can version-control. What the whole cluster should look like lives in Git, can be reviewed, can be traced — that’s the foundation of GitOps.

A minimal “desired state” looks like this:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3                # I want 3
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      containers:
        - name: web
          image: myrepo/web:1.0   # run this image

Then kubectl apply -f web.yaml. You never told it “start three containers”; you only said “I want 3 of web:1.0” — the rest is up to the reconcile loop.

What a cluster looks like: the brain and the workers

So where does “the Controller keeps converging” actually happen? A K8s cluster has two halves:

you: kubectl apply (the YAML declaring your desired state) Control Plane · the brain API Serverthe only entry point Schedulerwhere each pod goes Controller Mgrruns the reconcile loops etcdstate store Worker Node kubelet Pod Pod Worker Node kubelet Pod Worker Node kubelet Pod Pod
The Control Plane is the brain (decides what to run, where to place it, keeps correcting the gap; all state lives in etcd); Worker Nodes are the workers, each running one kubelet that looks after the Pods on it
  • Control Plane (the brain): kubectl apply goes to the single entry point, the API Server; the Scheduler decides which machine a new pod lands on; the Controller Manager runs those reconcile loops; etcd stores the state of the whole cluster.
  • Worker Nodes (the workers): the machines that actually run your Pods, each with one kubelet looking after the pods on that machine.

You don’t need to memorise these components now — Pod, Node and Scheduler are the stars of the next post. For this one, just carve that loop into your head.

Reflections

K8s is hard, usually because people learn it in the wrong order

I’ve watched many people (myself included, back then) learn K8s starting from the API — memorising kubectl commands, YAML fields, a pile of resource types — and it hurt, and nothing connected. Later it clicked: grasp the reconcile loop first, then go back and look at each resource. Once you know “everything is: you declare a desired state, a controller pulls reality towards it”, the seemingly unrelated names — Deployment, ReplicaSet, Service, HPA — instantly become different applications of one pattern. Mental model first; only then do details have somewhere to hang. It’s exactly what I felt reading about the data engineering lifecycle.

”Declarative + version control” is what I admire most about K8s

What makes K8s beautiful to me isn’t that it auto-restarts containers; it’s that it turns “what the cluster should look like” into a version-controlled file. The desired state of the whole system lives in Git, can be reviewed, traced, rebuilt in one step — the same victory of engineering discipline as dbt turning data transformations into version-controlled code: move “the things that change” out of people’s heads and ad-hoc operations into a trackable declaration. The imperative world relies on “someone remembers how to fix it”; the declarative world relies on “a desired state everyone can see”.

But don’t adopt K8s because it’s fashionable

The customary cold water at the end: K8s is powerful, but it’s itself a mountain that needs operating. When you have one or two services and a team without a K8s background, forcing it in just swaps the trouble of “looking after containers” for the double trouble of “looking after containers + looking after K8s”. My priority has always been confirm the pain first, then bring in the heavy weapons: ask “do I really have so many, such messy things that I need an orchestrator” before deciding whether to walk into this mountain. Understanding its value and judging whether you should use it are two different things — this series helps with the former; the latter still comes back to your own pain.