← Learn··Updated 31 May 2026·6 min read

What Kubernetes actually is

Kubernetes is a control loop that makes reality match a YAML file you wrote. Here is the desired-state model, how it differs from Docker Compose, and when you actually need it.

Kubernetes
Kubernetes from scratch with k3sPart 1 of 9
#kubernetes
#k3s
#orchestration
#ai-assisted

Ask ten engineers what Kubernetes is and you will get ten answers: a container scheduler, a cloud platform, a YAML generator, a resume keyword. They are all describing the same thing from different angles, and none of them is the core idea. The core idea is smaller and stranger than any of those, and once it clicks the rest of the system stops looking arbitrary. This part is about that idea — what Kubernetes actually is, underneath the vocabulary.

level:Beginner

ℹ️ Read-along — concepts only; nothing to install. The examples are illustrative.

Container orchestration, plainly

Kubernetes is a container orchestrator. You already know how to run a container on one machine: docker run, and the container starts. Orchestration is the next problem up — running many containers across many machines, and keeping them running when machines or containers fail.

What does an orchestrator do?

An orchestrator answers the questions a single docker run cannot:

  • Where should this run? Given several machines with different amounts of free CPU and memory, pick one. This is scheduling.
  • What if it dies? If a container crashes, start it again. If the whole machine dies, start the container somewhere else.
  • How do I update it without downtime? Bring up the new version, check it is healthy, then retire the old one — never leaving a gap.
  • How do other things reach it? Containers come and go and their addresses change, so give them a stable name and spread traffic across the healthy ones.

Docker on a single host does none of these across machines. Kubernetes does all of them, continuously, as its entire job. That continuous part is the heart of it.

The idea that makes Kubernetes click: desired state

Here is the single concept everything else hangs off. You do not tell Kubernetes what to do. You tell it what you want, and it figures out the doing — over and over, forever.

What is a control loop?

The Kubernetes documentation uses a thermostat to explain this, and it is the right picture. When you set the temperature, that is telling the thermostat about your desired state. The actual room temperature is the current state. The thermostat acts to bring the current state closer to the desired state, by turning equipment on or off. You do not switch the heater on and off yourself; you set a target and the device maintains it.

Kubernetes works exactly this way. You write down what you want — "three copies of this image, reachable on this port" — and store it in the cluster. Then controllers, which are control loops that watch the state of your cluster, then make or request changes where needed. Each controller tries to move the current cluster state closer to the desired state.

flowchart TD
  A["You declare desired state<br/><i>want 3 replicas</i>"] --> B["Stored in the cluster"]
  B --> C["Controller observes<br/><i>current state</i>"]
  C --> D{"Match desired?"}
  D -->|"yes"| E["Do nothing, watch again"]
  D -->|"no"| F["Act: start or stop a pod"]
  F --> C
  E --> C

The control loop never ends. It observes reality, compares it to your declaration, acts on any gap, and repeats — forever.

This is why a Kubernetes object has a spec field. These objects have a spec field that represents the desired state. The controller(s) for that resource are responsible for making the current state come closer to that desired state. You edit the spec; the controllers do the work of reconciling.

The practical payoff is self-healing. Kill a container by hand and it comes back, because you declared you wanted it and the loop notices it is missing. Drain a machine for maintenance and the work relocates, because the declaration says nothing about which machine. You stop managing individual containers and start managing intent.

There is a subtlety worth naming, because it explains why Kubernetes is so robust. The reconciliation loop is level-triggered, not edge-triggered. An edge-triggered system reacts to events: "a pod died, run the restart handler." If that one event is missed — the controller was restarting, the message was dropped — the action never happens. A level-triggered system instead looks at the current level of reality each time it runs and acts on whatever gap it finds, regardless of what events led there. So even if a controller misses the moment a pod died, the next time it observes the cluster it simply sees "two pods exist, three are wanted" and fixes it. The loop is self-correcting because it always re-derives the work from the present state rather than trusting a history of events.

💡 Tip Whenever Kubernetes confuses you, ask two questions: what is the desired state here, and which controller is responsible for reconciling it? Almost every behaviour in the system is some controller closing the gap between what you declared and what currently exists.

Kubernetes versus Docker Compose

This is the comparison that makes the model concrete, because most people arrive from Docker Compose. Compose and Kubernetes look similar — both are YAML where you declare services — but they differ on two axes that matter a great deal.

One host versus a cluster

Compose runs your services on one machine. That is its scope by design, and it is wonderfully simple: one file, one host, docker compose up. Kubernetes runs across a cluster of machines and treats them as a pool of resources. It decides which machine each workload lands on, and moves work between machines when one fails. The single-host limit is the wall Compose eventually hits — when that host reboots, everything on it goes down with it.

Imperative versus declarative reconciliation

This is the subtler difference. Compose is declarative in that you describe services in a file — but nothing watches the running state afterwards. Run docker compose up -d and Compose makes the world match the file at that moment, then stops caring. If a container later dies and its restart policy gives up, it stays dead until you run a command. Compose acts when you tell it to.

Kubernetes never stops watching. The declaration lives inside the cluster, and the control loop reconciles toward it continuously. Nobody has to run a command for a crashed pod to come back. That always-on reconciliation is what self-healing, rolling updates, and node failover are all built from.

flowchart LR
  subgraph C["Docker Compose"]
    A["You run a command"] --> B["Match file once<br/><i>then stop</i>"]
  end
  subgraph K["Kubernetes"]
    D["You store desired state"] --> E["Loop reconciles<br/><i>continuously, no command</i>"]
  end
  C -->|"add a cluster + a control loop"| K

Compose acts when you tell it to; Kubernetes acts on its own, forever, to hold the state you declared.

⚠️ Warning Do not read this as "Compose is broken." It is not — it does exactly what it promises on one host. The gotcha is expecting Compose to self-heal or fail over. It will not, because nothing is watching after the command finishes. That is a feature boundary, not a bug.

When you actually need it — and when you do not

Honesty matters more than hype here. Kubernetes is a large step up in complexity. You are trading a Compose file you can read in one sitting for a distributed system with its own networking, storage, certificates, and upgrade model. Most homelabs and small projects never need it.

You have a real problem Kubernetes solves when:

  • Downtime during reboots is unacceptable. One host means patching it takes everything down. A cluster reschedules the work first.
  • You need zero-downtime deploys. Rolling updates that bring up the new version before retiring the old are built in.
  • You outgrow one machine, or want software-level self-healing across several.

You almost certainly do not need it when one well-backed-up Docker host runs your handful of services happily. "Compose is enough" is a perfectly good, often permanent, answer. From Docker to k3s makes this case in detail — read it before you commit to the jump.

It is also worth being clear-eyed that the failover Kubernetes gives you is only as real as the hardware underneath it. A cluster of three virtual machines on one physical host protects you against software failures — a crashed process, a bad deploy, a node you want to patch — because the work moves to a surviving VM. It does not protect you against the physical box dying, because all three VMs die with it. Real hardware high availability needs more than one physical machine. For learning and for most homelabs, software-level self-healing on a single host is plenty; just know which kind of resilience you are buying.

ℹ️ Note The single biggest reason people overreach for Kubernetes is mistaking complexity you can see in a diagram for capability you actually need. The diagrams are impressive. That is not a reason to run one.

k3s is real Kubernetes, just lighter

One last thing to clear up, because it trips up beginners: learning on k3s does not mean learning a watered-down version. k3s is a fully compliant Kubernetes distributionCNCF-certified, with the same API and the same objects as any other Kubernetes.

What k3s strips out is operational weight, not features. It packages the whole control plane into a single binary of less than 100 MB and uses SQLite as the default datastore instead of a standalone etcd cluster, which is the main thing that makes a standard install painful. Everything you learn on k3s — the desired-state model, pods, deployments, services — is identical on a managed cluster at work. You are learning the real thing on an easier-to-run package of it.

A short close

Strip away the vocabulary and Kubernetes is one idea wearing many hats: declare what you want, and let a control loop hold reality to it. Compose declares state once and stops; Kubernetes declares state and never stops reconciling — across a cluster, not a single host. That difference is the entire reason it exists, and the reason it is heavy.

Next up, the machines themselves: clusters, the control plane, and nodes takes apart the "brain and the workers" that run the control loops you just met. If you want the full path, the series hub lists all nine parts in order.