Day 1: Your First Cluster

The win

kubectl get nodes prints one node, STATUS Ready, on your own machine. That is the whole point of today.

Why this matters for your mission

You want to learn Kubernetes. k3s on this box is a real, standard Kubernetes cluster, and everything you learn on it transfers to any cluster. Your homelab services (PaperMC, Grafana, Nextcloud) will become useful practice targets along the way, but today is about the platform itself. Until the API server answers, none of the rest of the week exists.

You already know more than you think

Compose is a degenerate Kubernetes. That table in the README is the bridge:

  • restart: always → a Deployment controller keeps desired state
  • docker pskubectl get pods
  • docker compose scalekubectl scale deployment
  • healthcheck: in compose → liveness / readiness probes

So today is not a new world. It is your world with a control plane bolted on.

The one mental model to internalize today

Kubernetes is a declarative control loop. You declare desired state (a manifest); controllers reconcile reality toward it forever. There is no “start this container” command. When you kubectl delete pod, the Deployment controller sees 2 of 3 replicas and immediately creates a replacement. Nobody “restarts” anything; desired state is reconciled.

Do this now (real commands, on your box)

Three steps, each with a verify. Follow 10.11 - Install and First Cluster in detail; the recap is here.

Step 1 · Enable k3s on NixOS

On your machine the k3s service already exists but is inactive (probe found it). You need the module enabled with Traefik and servicelb disabled, because Caddy owns host ports 80/443:

{ pkgs, ... }:
{
  services.k3s = {
    enable = true;
    role = "server";
    extraFlags = ''
      --write-kubeconfig-mode 644
      --disable traefik
      --disable servicelb
    '';
  };
  environment.systemPackages = with pkgs; [ kubectl ];
}

Then rebuild: sudo nixos-rebuild switch --flake ~/nix#<your-host>

Watch out If you re-enable Traefik/servicelb later without freeing 80/443, pods will crashloop on port conflicts. Keep them disabled for week 1; use port-forward and NodePort (30000-32767) instead.

Step 2 · Verify the API is alive

systemctl status k3s                 # active (running)
kubectl get nodes -o wide            # one node, STATUS=Ready
kubectl get pods -A                  # coredns + metrics-server + local-path
kubectl cluster-info                 # control plane reachable
If it is slow First start pulls images; pods can sit in ContainerCreating for 60-120s. That is normal, not broken.

Step 3 · First pod, first deployment (the day-1 exercise)

kubectl run hello --image=nginx:alpine      # throwaway smoke test
kubectl get pods; kubectl logs hello; kubectl delete pod hello

kubectl create deployment hello --image=nginx:alpine --replicas=2
kubectl get deployments,replicasets,pods
kubectl port-forward deployment/hello 8080:80   # open http://localhost:8080
kubectl exec -it deployment/hello -- bash
kubectl logs deployment/hello --tail=20
kubectl delete deployment hello
Habit to start today Imperative kubectl is fine for throwaway experiments. For anything you want to keep, write a manifest and kubectl apply -f. That is the declarative habit your mission depends on.

Check your understanding

One attempt per question, then the feedback. Say the answer in your head before clicking.

You delete a pod that a Deployment owns. What happens next, and why?

Why are Traefik and servicelb disabled in this setup?

What is the smallest unit Kubernetes schedules, and what assumption should you make about it?

When you are done

  • kubectl get nodes shows Ready.
  • You ran a deployment, port-forwarded it, exec’d in, and read its logs.
  • You can say what happens when a Deployment-owned pod dies, in one breath.

Primary source for this lesson

Chapter 1 of Kubernetes in Action, 2nd ed (Lukša) covers exactly this ground. The k3s install details are in docs.k3s.io. Read one of them today if you can.

Ask your teacher Anything unclear? Ask your teacher agent anything about this lesson, the commands, or the mission. If a command fails, paste the output here.