What Kubernetes is
The problem it solves, in plain terms.
You wrote an app and packaged it into a container: the program plus what it needs to run, so it behaves the same on any machine. One copy on a laptop is a single command. The hard part is many copies across many machines: restart the ones that crash, move work off a dead server, and roll out new versions without going dark. Doing that by hand is a full-time job. Kubernetes does it for you.
The one idea that makes it click
You do not give Kubernetes a list of steps. You declare the end state you want, for example "keep three copies of my app running," and it keeps comparing live objects to that declaration. If a copy dies, it starts a replacement without being asked. The cluster is maintaining the state you set, not waiting for the next command.
Imperative automation is a fixed list of steps. If one step cannot run, the rest of the plan stalls. Kubernetes is declarative: you name the destination state, and controllers keep working out how to get there, including around a failed node or a crashed pod.
People call this a container orchestrator, which is a fancy way of saying it runs, connects, heals, and updates lots of containers for you. You'll also see the name written K8s: the letter K, then eight letters, then s. It grew out of Google's experience running containers at huge scale, and it behaves the same everywhere. The same app description runs on your laptop, in a company data center, or on Amazon, Google, or Microsoft's cloud, so you aren't locked to one vendor. Learn it once and the skills carry over wherever you work.
Where your app actually runs
Kubernetes does not live on a single computer. It ties a group of machines together so they act like one system. That group is a cluster. Each machine is a node. Most nodes are workers: they run your app. The control plane decides and remembers what you asked for. You rarely log into a worker. You talk to the control plane, and it assigns work to the workers.
Talking to the cluster with kubectl
You talk to the control plane with kubectl. That is a command-line tool: you type commands instead of clicking. People say "kube-control" or "kube-cuttle," and no one really agrees. Every kubectl command is a request from your machine to the cluster. A good first one lists the machines in the cluster.
$ kubectl get nodesNAME STATUS ROLES AGE VERSIONkind-control-plane Ready control-plane 9m v1.31.0kind-worker Ready <none> 8m v1.31.0kind-worker2 Ready <none> 8m v1.31.0
Kubernetes is not a fancy way to run one container on your laptop. It is a control loop that keeps a whole fleet of containers matching the state you declared. You say "three copies of this app, behind this address, with this config." The cluster compares live reality to that wish and nudges things until they match. That is why operators talk about desired state instead of a checklist of start scripts.
On-call, this mental model matters more than memorizing every YAML field. When something is wrong, ask what the desired state says and what the live objects actually look like. The gap between those two views is almost always where the incident lives. Imagine an attacker already has a foothold in one pod on your production cluster: the same desired-state machinery that heals crashes will also recreate anything you delete unless you change the declaration that keeps recreating it.
Prefer reading the API with kubectl get and kubectl describe over guessing from a dashboard screenshot. The API is the source of truth the controllers read. A dashboard is a delayed sketch of that truth.
Try this
Talk to a real (or kind/minikube) cluster and prove you can see nodes and create a throwaway pod. You want Ready nodes and a Running pod so the "desired state" idea stops being abstract.
$ kubectl get nodesNAME STATUS ROLES AGE VERSIONkind-control-plane Ready control-plane 12d v1.30.0kind-worker Ready <none> 12d v1.30.0$ kubectl run demo --image=nginx:1.27 --restart=Neverpod/demo created$ kubectl get pods demo -o wideNAME READY STATUS RESTARTS AGE IP NODEdemo 1/1 Running 0 8s 10.244.1.7 kind-worker$ kubectl delete pod demopod "demo" deleted
Takeaway
Kubernetes is a desired-state engine: you declare what should be true, controllers close the gap. Verify with kubectl against the API, not against a hunch — and remember that healing will recreate whatever your declaration still asks for.
Run something right now
Enough describing it. Let's make Kubernetes run something for real. The command below starts nginx, a small and popular free web server (a program that answers requests coming from web browsers), as a quick throwaway pod named hello. A pod is the smallest unit Kubernetes runs, and it usually holds a single container: your app. When you press enter, the cluster finds a node with room, pulls down the nginx software, and starts it. A few seconds later it's serving.
$ kubectl run hello --image=nginxpod/hello created$ kubectl get podsNAME READY STATUS RESTARTS AGEhello 1/1 Running 0 12s
That one-liner is great for a quick poke around. For real work, you write the state you want into a file and apply that file. Then it lives in version control, a system that tracks every change to your files over time, so a teammate can review it and you can run it again exactly the same way later. These files are written in YAML, a plain-text format that describes settings as simple labels, values, and lists. Here's the same web server written out in full, as a pod named web.
apiVersion: v1kind: Podmetadata:name: weblabels:app: webspec:containers:- name: webimage: nginx:1.27ports:- containerPort: 80
$ kubectl apply -f pod.yamlpod/web created$ kubectl apply -f pod.yamlpod/web unchanged
Run apply a second time and Kubernetes reports unchanged. It compared your file to what is already running, found no difference, and did nothing. You describe what you want; it only acts on the gap between that and reality.
When a pod won't start
Pods don't always come up clean, and learning to read a failure is half the job. The most common first stumble is a typo in the image tag: ask for one that doesn't exist and the pod gets stuck. kubectl get pods flags the trouble in the STATUS column, and kubectl describe pod explains why at the bottom, under a heading called Events.
$ kubectl run oops --image=nginx:1.99pod/oops created$ kubectl get podsNAME READY STATUS RESTARTS AGEoops 0/1 ImagePullBackOff 0 45s$ kubectl describe pod oops...Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 45s default-scheduler Successfully assigned default/oops to kind-workerNormal Pulling 18s (x3 over 45s) kubelet Pulling image "nginx:1.99"Warning Failed 17s (x3 over 44s) kubelet Failed to pull image "nginx:1.99": manifest not foundWarning Failed 17s (x3 over 44s) kubelet Error: ErrImagePullNormal BackOff 4s (x4 over 44s) kubelet Back-off pulling image "nginx:1.99"
Read the Events from top to bottom like a short story. The scheduler picked a node, the kubelet on that node tried to pull nginx:1.99, and there is no such tag, so it keeps backing off and retrying. That status, ImagePullBackOff, almost always means a wrong image name or tag. Fix it to a real one like nginx:1.27 and the same pod comes up Running.