Kubernetes basics · Lesson 2 of 12 · about 25 minutes

Your first cluster, free on your laptop

Build a real three-node Kubernetes cluster on your own machine in about a minute, look inside it, and watch it repair itself.

By the end you'll have

  • A three-node Kubernetes cluster running on your laptop, for free
  • Seen the control plane and worker nodes from Lesson 1 with your own eyes
  • Deleted a pod and watched Kubernetes replace it

What you need

You'll use kind, short for "Kubernetes in Docker". It runs each node of the cluster as a Docker container on your laptop. It's what many Kubernetes projects use for testing, it starts in about a minute, and you can delete it just as fast. It's not for production; it's perfect for learning.

You need three things:

  • Docker, running. Docker Desktop on macOS or Windows, or Docker Engine on Linux.
  • kubectl (say "cube control"), the command-line tool you use to talk to any Kubernetes cluster.
  • kind itself.

1. Install kind and kubectl

On macOS with Homebrew:

BASH
brew install kind kubectl

On Windows with Chocolatey:

POWERSHELL
choco install kind kubernetes-cli

On Linux, follow the download steps in the kind quick start (opens in a new tab).

Check that both work:

BASH
kind version
kubectl version --client

2. Describe the cluster you want

Remember desired state from Lesson 1? Creating the cluster works the same way. Save this as kind-learn.yaml:

YAML
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane   # the brain
  - role: worker          # a machine that runs your apps
  - role: worker          # and another one

3. Create it

BASH
kind create cluster --name learn --config kind-learn.yaml

This takes a minute or two the first time, while Docker downloads the node image. When it finishes, kind also points kubectl at the new cluster for you.

If your laptop struggles, drop the config and run kind create cluster --name learn. You get a single node that is both control plane and worker. Everything below still works; you'll just see one node instead of three.

4. Look at your nodes

BASH
kubectl get nodes
TEXT
NAME                  STATUS   ROLES           AGE   VERSION
learn-control-plane   Ready    control-plane   60s   v1.xx.x
learn-worker          Ready    <none>          40s   v1.xx.x
learn-worker2         Ready    <none>          40s   v1.xx.x

Three machines, all Ready. Your version numbers will differ, and that's fine. A ROLES value of <none> just means "an ordinary worker".

Here's what you just built:

How Kubernetes worksYou write the desired state in a file and send it to the cluster with kubectl apply. The control plane receives it: the API server takes the file, the scheduler picks a node for each pod, and controllers keep comparing what you asked for with what is actually running. The control plane runs pods on the worker nodes, and the nodes report back what is really running. If a pod or a node fails, controllers notice the difference and fix it.Youwrite the desiredstate in a filereplicas: 2kubectl applyControl planethe brain of the clusterAPI serverthe front door: takes your fileSchedulerpicks a node for each podControllersthe thermostat: compare wantedwith actual, fix it, repeatruns podsreports backWorker nodes: the machinesNode 1PodhelloPodapiNode 2Podhelloroom formoreIf a pod or a whole node fails, controllers see 1 copy instead of 2 and start a new one.
The middle box from Lesson 1, opened up. The control plane decides what should run where; the worker nodes run your containers, packaged as pods. In your kind cluster, the control plane is the node called learn-control-plane, and the two workers are learn-worker and learn-worker2. You only ever talk to the API server.

5. Find the control plane

The control plane is made of programs, and in your kind cluster they run as pods in a namespace called kube-system. (A namespace is a folder for grouping things; Lesson 10 covers them.)

BASH
kubectl get pods -n kube-system
TEXT
NAME                                          READY   STATUS    RESTARTS   AGE
coredns-xxxxxxxxxx-xxxxx                      1/1     Running   0          2m
coredns-xxxxxxxxxx-xxxxx                      1/1     Running   0          2m
etcd-learn-control-plane                      1/1     Running   0          2m
kindnet-xxxxx                                 1/1     Running   0          2m
kube-apiserver-learn-control-plane            1/1     Running   0          2m
kube-controller-manager-learn-control-plane   1/1     Running   0          2m
kube-proxy-xxxxx                              1/1     Running   0          2m
kube-scheduler-learn-control-plane            1/1     Running   0          2m

Your list is a little longer (some pods run once per node) and the random letters will differ.

What each part does

Lesson 1 gave you one line per part. Here's the fuller picture, including what happens when each one stops, which is the question that matters when something breaks (and a favorite in interviews).

The control plane

  • API server (kube-apiserver): the front door. Every request goes through it: yours from kubectl, the scheduler's, the kubelets'. It checks who's asking and whether they're allowed, then records the change. Nothing else talks to etcd directly. If it stops: your apps keep running, and each kubelet still restarts crashed containers on its own node, but nothing can be changed, scheduled or replaced, and kubectl stops answering.
  • etcd (etcd-learn-control-plane): the memory. A small database that holds everything the cluster knows: your desired state and the current status of every object. If it stops: the same as losing the API server. If its data is lost with no backup, the cluster forgets everything you've asked it to run, which is why managed providers back it up for you.
  • Scheduler (kube-scheduler): the seating planner. When a new pod needs a home, it checks which nodes have enough room (CPU and memory, Lesson 9) and picks one. It only decides; it doesn't start anything. If it stops: running pods are fine, but new pods wait in Pending with nowhere to go.
  • Controller manager (kube-controller-manager): the thermostats. Many small loops, one for each kind of thing, each comparing what you asked for with what exists. The one for Deployments is what replaces the pod you delete in step 6. If it stops: a container that crashes still gets restarted by its kubelet, but a pod that's deleted, or lost with a failed node, is never replaced.

On every node

  • Kubelet: the caretaker. An agent on each machine. It asks the API server what should run on its node, tells the container runtime to start it, restarts containers that crash, and reports back. It's the "reports back" arrow in the diagram. If it stops: the node is marked NotReady, and after a few minutes its pods are recreated on other nodes.
  • Container runtime (containerd): the engine. The software that actually runs containers. Kubernetes never runs a container itself; it asks the runtime to.
  • kube-proxy (kube-proxy-xxxxx): the switchboard. It sets up the network rules that send traffic to the right pods. Lesson 8 covers it.

Two of these, the kubelet and the container runtime, aren't in your pod list. They run directly on each node, underneath Kubernetes, because something has to be there to start the pods in the first place.

The rest of the list is helpers: coredns is the cluster's phone book, turning names into addresses, and kindnet is kind's network plugin, which gives every pod its own address.

6. Watch it heal

Now try the idea from Lesson 1 for real. Ask for two copies of a web server:

BASH
kubectl create deployment hello --image=nginx:1.27 --replicas=2
kubectl get pods -o wide

The NODE column shows the scheduler spread your two pods across the workers. Copy the name of one pod, then delete it:

BASH
kubectl delete pod <paste-a-pod-name-here>
kubectl get pods

There are still two pods. One of them is brand new: look at its AGE. You told Kubernetes "two copies", one disappeared, and a controller noticed the difference and fixed it. You didn't restart anything. (Lesson 5 explains Deployments properly.)

Also notice that neither pod landed on learn-control-plane. That node has a taint, a "keep out" sign that tells the scheduler not to put ordinary apps there, so the brain of the cluster keeps its resources for itself. (On the one-node cluster, kind removes that taint so your apps have somewhere to run, and everything lands on that one node.)

Optional: choose the node yourself

Normally the scheduler picks. You can narrow its choice by giving a node a label and asking for that label. Label one worker:

BASH
kubectl label node learn-worker2 disk=ssd

Save this as pinned.yaml (Lesson 3 explains pod files properly):

YAML
apiVersion: v1
kind: Pod
metadata:
  name: pinned
spec:
  nodeSelector:
    disk: ssd          # only run on nodes with this label
  containers:
    - name: web
      image: nginx:1.27
BASH
kubectl apply -f pinned.yaml
kubectl get pod pinned -o wide

The NODE column says learn-worker2, every time. On the one-node cluster, label learn-control-plane instead.

In real clusters you'd use this when some machines are different, like nodes with fast disks or graphics cards (GPUs). Lesson 9 covers the other ways: pinning a pod to one exact node, softer "preferred" rules, and taints.

Which cluster am I talking to?

kubectl can know about many clusters at once, and it sends commands to whichever one is current. Get into the habit of checking before you delete anything:

BASH
kubectl config current-context

For this lesson it should say kind-learn. If you ever have a work or production cluster on the same laptop, this one command is what keeps a practice delete from landing in the wrong place.

On a managed cluster, the control plane disappears

Your kind cluster shows everything, because you run all of it. A managed cluster from a cloud provider (EKS, AKS, GKE, DigitalOcean and others) looks different, because the provider runs the control plane for you, out of sight. If you have access to one, at work or on a free trial, you can see this for yourself:

BASH
kubectl get nodes
kubectl get pods -n kube-system
kubectl cluster-info
  • get nodes lists only worker nodes. There's no control-plane node.
  • get pods -n kube-system shows networking and DNS pods, but no kube-apiserver, etcd, kube-scheduler or kube-controller-manager.
  • cluster-info still shows an API server address, but it belongs to the provider, not to any machine you can see.

That's what "managed Kubernetes" means: you rent the workers, and the provider keeps the brain running, patched and backed up. Everything you type with kubectl works the same either way. Run kubectl config current-context first, so you know which cluster you're looking at.

Every major cloud offers managed Kubernetes the same way, and everything in this track works on all of them. If you're curious how they compare, see Managed Kubernetes compared.

Clean up

When you're done, delete the whole cluster. It's just Docker containers, so this takes seconds:

BASH
kind delete cluster --name learn

You can create a fresh one any time with the command from step 3. In Lesson 3 you will, to look closely at pods.

Check yourself

  1. What is kind?

  2. Which control plane component picks a node for each new pod?

  3. You deleted one of your two hello pods and a new one appeared. What made that happen?

  4. Why does etcd matter so much?

  5. On a managed cluster like EKS or DOKS, why is there no kube-apiserver pod?

  6. Which command should you run before deleting anything, to make sure you're on the right cluster?

Key terms

  • Control plane: the part of the cluster that decides what runs where and keeps checking it.
  • Worker node: a machine that runs your pods.
  • kubectl: the command-line tool for talking to a cluster's API server.
  • etcd: the database where the cluster stores its desired state.
  • Kubelet: the agent on each node that starts and watches its pods.
  • Context: kubectl's name for "which cluster, as which user". kubectl config current-context shows the active one.

Go deeper