KUBERNETES TUTORIAL

k8s

You're connected to a real 3-node cluster that's already running a small app. We won't deploy anything today. We'll learn what a cluster is made of, read its state with `kubectl`, and watch Kubernetes heal itself.

What we're doing

When you hit Start, a real cluster is already up (k3d-firstlook: one control-plane node and two workers) running a shop app. You'll use kubectl to look around: which cluster you're on (contexts), what machines exist (nodes), what's running (pods), and where it's running. Then you'll delete a pod and watch the cluster replace it on its own.

Watch the video first, then run these as you read. Every command and flag is explained. kubectl is already set up for you here; nothing needs sudo.

The one idea: desired state

With Docker you give an order: "start this container." With Kubernetes you declare a wish: "keep 3 of these running, always." Kubernetes then runs a loop forever, comparing what you asked for against what's actually running, and fixing any gap. Kill a pod and it starts another, because two is not the three you asked for. That one loop is behind self-healing, scaling, and rollouts. Hold onto it; you'll see it live in Step 6.

Step 1: Which cluster am I on?

Always start here. A context is a saved bundle of "which cluster, which user, which namespace," under one name.

kubectl config get-contexts
CURRENT   NAME            CLUSTER         AUTHINFO              NAMESPACE
*         k3d-firstlook   k3d-firstlook   admin@k3d-firstlook
          staging         staging         staging-admin         web

The * marks the context you're pointed at: k3d-firstlook, the real one. The staging entry is here to show what a second cluster looks like in the list (in a real job you'd have dev, staging, prod). You switch with:

kubectl config use-context k3d-firstlook    # (you're already on it)

Habit that saves you: before running anything that changes a cluster, check the *. Reading the wrong cluster is harmless; acting on the wrong one is not.

Step 2: What machines are in the cluster?

kubectl get nodes -o wide
NAME                     STATUS   ROLES                  VERSION
k3d-firstlook-server-0   Ready    control-plane,master   v1.31.5+k3s1
k3d-firstlook-agent-0    Ready    <none>                 v1.31.5+k3s1
k3d-firstlook-agent-1    Ready    <none>                 v1.31.5+k3s1

kubectl get nodes lists the machines (nodes) in the cluster. Three, all Ready. The ROLES column is the thing to read:

  • server-0 is the control-plane: the brain that stores the desired state and decides where things run.
  • the two agent nodes are workers: where your containers actually run.

-o wide just adds extra columns. You talk to the control plane with kubectl; you never log into the nodes.

Step 3: What's actually running?

kubectl get pods -A
NAMESPACE     NAME                          READY   STATUS    RESTARTS   AGE
kube-system   coredns-...                   1/1     Running   0          5m
kube-system   local-path-provisioner-...    1/1     Running   0          5m
kube-system   metrics-server-...            1/1     Running   0          5m
shop          cache-...                     1/1     Running   0          4m
shop          web-...                       1/1     Running   0          4m
shop          web-...                       1/1     Running   0          4m
shop          web-...                       1/1     Running   0          4m

A Pod is the smallest unit you run; it wraps your container. -A means all namespaces. Two groups:

  • kube-system: Kubernetes running its own internals (coredns is in-cluster DNS, the others are helpers). Ignore these day to day.
  • shop: the actual app, a cache and three web pods.

READY 1/1 and STATUS Running mean healthy. Those three web pods are the "I want 3" wish, alive in front of you.

A Namespace is just a folder that groups things. -A shows every namespace; later we use -n shop to look at just one.

Step 4: Where is the app running?

kubectl get pods -n shop -o wide
NAME         READY   STATUS    NODE                     IP
web-...      1/1     Running   k3d-firstlook-server-0   10.42.2.4
web-...      1/1     Running   k3d-firstlook-agent-0    10.42.0.4
web-...      1/1     Running   k3d-firstlook-agent-1    10.42.1.3
cache-...    1/1     Running   k3d-firstlook-agent-1    10.42.1.4

-n shop narrows to that one namespace; -o wide adds the NODE column. Notice the three web pods are on three different nodes, one each. You never asked for that, the scheduler spread them so that one machine dying can't take out all your copies at once. That's orchestration doing its job, visible in one column.

Step 5: Zoom into one pod

get is the wide view; describe is the zoom. Copy one web pod name from above and:

kubectl describe pod -n shop <web-pod-name>

You get everything about that pod: its node, its image, and an Events list at the bottom that reads like a diary (scheduled, pulled image, started). When a pod misbehaves, that Events section is the first place you look. Right now it just tells the happy startup story.

Step 6: Watch it heal itself

The payoff. The wish is "3 web pods, always." Break it and watch.

In one terminal, start a live watch:

kubectl get pods -n shop -w

-w means watch: the list stays live and updates as things change. Leave it running. In a second terminal, delete one web pod (use a real name from Step 4):

kubectl delete pod -n shop <web-pod-name>

Flip back to the watching terminal. You'll see:

web-...   1/1   Terminating          # the one you deleted
web-xyz   0/1   ContainerCreating    # a brand new one, seconds later
web-xyz   1/1   Running              # back to 3

You didn't restart anything. The Deployment saw two pods when it wanted three and created a replacement, in seconds, on its own. That's self-healing, the clearest reason Kubernetes exists. Stop the watch with Ctrl+C.

The objects you just met

Object One-liner
Pod wraps your container; the smallest thing you run
ReplicaSet keeps the right number of identical pods
Deployment "keep N of these running, this version" (owns a ReplicaSet)
Service one stable address in front of a set of pods
Namespace a folder that groups objects (like shop)
Node a machine in the cluster (control-plane or worker)

The chain to remember: a Deployment owns a ReplicaSet, which keeps the right number of Pods, each running on a Node, with a Service as the front door.

Cheat sheet

kubectl config get-contexts          # which cluster am I on? (* = current)
kubectl config use-context <name>    # switch clusters
kubectl get nodes -o wide            # the machines in the cluster
kubectl get pods -A                  # everything running, all namespaces
kubectl get pods -n shop -o wide     # one namespace, with the NODE column
kubectl describe pod -n shop <name>  # zoom into one pod + its events
kubectl get pods -n shop -w          # live watch (Ctrl+C to stop)
kubectl delete pod -n shop <name>    # delete one, and watch it come back

The one thing to remember: you declare the state you want, and Kubernetes works forever to keep reality matching it. Everything else (scheduling, self-healing, scaling, rollouts) is that one idea at work.

Next tutorial: we deploy our own app onto this cluster.


What's next

Now go and try this out in a live environment — boot a fresh cluster and play with the manifests above.

Start Kubernetes
Spec 2 CPU / 5 GiB ·Disk 20 GiB ·Lifetime 7 days
Up next in Apache Airflow Mastery Chapter 3 of 5

DAG Patterns & Best Practices

Continue