Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lab: Your First Cluster — Minikube Setup & Exploration

⏱️ ~30 min hands-on

Prerequisitesminikube, kubectl, and Docker installed
Difficulty🟢 Beginner
What you’ll doStart a cluster, explore every component, poke the API Server directly

Objectives

  • Start a Minikube cluster and verify all control plane components are running
  • Inspect a node and understand what the output means
  • Navigate the cluster using kubectl get, describe, and cluster-info
  • Access the Kubernetes Dashboard
  • Call the API Server directly with curl

Setup

# Verify your tools are installed
kubectl version --client
minikube version
docker version

# Start minikube with 2 CPUs and 2GB RAM
minikube start --cpus=2 --memory=2048

Expected output:

😄  minikube v1.33.x on Linux
✨  Using the docker driver based on existing profile
👍  Starting "minikube" primary control-plane node in "minikube" cluster
🚜  Pulling base image v0.0.44 ...
🔄  Restarting existing docker container for "minikube" ...
🐳  Preparing Kubernetes v1.30.x on Docker 26.x.x ...
🔎  Verifying Kubernetes components...
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

Exercise 1: Verify the Cluster is Healthy

What we’re doing: Check that all control plane components are running and the node is ready.

kubectl cluster-info

Expected output:

Kubernetes control plane is running at https://192.168.49.2:8443
CoreDNS is running at https://192.168.49.2:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

💡 What just happened? cluster-info shows the API Server URL and any running cluster services. The IP 192.168.49.2 is the Minikube VM’s internal IP.

# Check node status
kubectl get nodes

Expected output:

NAME       STATUS   ROLES           AGE   VERSION
minikube   Ready    control-plane   5m    v1.30.x
# Get more detail
kubectl get nodes -o wide

Expected output:

NAME       STATUS   ROLES           AGE   VERSION    INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION   CONTAINER-RUNTIME
minikube   Ready    control-plane   5m    v1.30.x    192.168.49.2   <none>        Ubuntu 22.04.4 LTS   5.15.x           containerd://1.7.x

Note the CONTAINER-RUNTIME column — you can see containerd is what’s actually running your containers.


Exercise 2: Inspect the Control Plane Pods

What we’re doing: Kubernetes runs its own control plane as pods in the kube-system namespace.

kubectl get pods -n kube-system

Expected output:

NAME                               READY   STATUS    RESTARTS   AGE
coredns-5dd5756b68-abcde           1/1     Running   0          10m
etcd-minikube                      1/1     Running   0          10m
kube-apiserver-minikube            1/1     Running   0          10m
kube-controller-manager-minikube   1/1     Running   0          10m
kube-proxy-xxxxx                   1/1     Running   0          10m
kube-scheduler-minikube            1/1     Running   0          10m
storage-provisioner                1/1     Running   0          10m

💡 What just happened? The control plane runs as pods! Each component (etcd, API server, scheduler, controller manager) is a pod managed by the kubelet. This is called a static pod — defined directly in /etc/kubernetes/manifests/ on the node, not via the API.

# Describe the API server pod
kubectl describe pod kube-apiserver-minikube -n kube-system | head -30

Look at the Image: line — you’ll see the exact version of the API server binary being used.


Exercise 3: Deeply Inspect the Node

kubectl describe node minikube

This is a long output. Here’s what to focus on:

# Pipe through grep to extract key sections
kubectl describe node minikube | grep -A5 "Conditions:"
kubectl describe node minikube | grep -A5 "Allocatable:"
kubectl describe node minikube | grep -A10 "Allocated resources:"

What to look for:

SectionWhat it tells you
ConditionsIs the node healthy? DiskPressure, MemoryPressure, Ready
AllocatableHow much CPU/memory pods can use
Allocated resourcesHow much is already used by running pods
EventsRecent node-level events

Exercise 4: Explore All Namespaces

What we’re doing: Everything in K8s lives in a namespace. Let’s see what’s already there.

kubectl get namespaces

Expected output:

NAME              STATUS   AGE
default           Active   15m
kube-node-lease   Active   15m
kube-public       Active   15m
kube-system       Active   15m
NamespacePurpose
defaultWhere your workloads go unless you specify otherwise
kube-systemK8s internal components
kube-publicReadable by all; used for cluster info bootstrap
kube-node-leaseNode heartbeat lease objects
# See EVERYTHING in every namespace
kubectl get all --all-namespaces

Exercise 5: Access the Dashboard

minikube dashboard

💡 What just happened? Minikube opens a web browser with the Kubernetes Dashboard — a visual UI for the cluster. You can see pods, deployments, services, and more. It’s useful for exploration but not recommended for production management.

The dashboard opens automatically. Explore:

  • Workloads → Pods → see the kube-system pods
  • Cluster → Nodes → see node resource usage

Press Ctrl+C to stop when done.


Exercise 6: Talk to the API Server Directly

Every kubectl command is just an HTTP request. Let’s see the raw API.

# Start a proxy to the API Server (runs in background)
kubectl proxy --port=8001 &

# Now call the API directly with curl
curl http://localhost:8001/api/v1/namespaces

Expected output (truncated):

{
  "kind": "NamespaceList",
  "apiVersion": "v1",
  "items": [
    { "metadata": { "name": "default" } },
    { "metadata": { "name": "kube-system" } }
  ]
}
# List pods in kube-system via raw API
curl http://localhost:8001/api/v1/namespaces/kube-system/pods | python3 -m json.tool | grep '"name"' | head -10

# Stop the proxy
kill %1

💡 What just happened? You bypassed kubectl entirely and spoke directly to the Kubernetes API Server. This is exactly what kubectl does under the hood — it formats HTTP requests and pretty-prints the JSON responses.


🔥 Break It! Challenge

Understand what happens when a control plane pod “disappears.”

# On minikube, static pods are managed by the kubelet from manifests
minikube ssh "ls /etc/kubernetes/manifests/"

Expected output:

etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml

These files define the control plane pods. If you delete one, the kubelet immediately recreates it. Try it:

# Move the scheduler manifest (simulating a crash)
minikube ssh "sudo mv /etc/kubernetes/manifests/kube-scheduler.yaml /tmp/"

# Watch the scheduler disappear
kubectl get pods -n kube-system -w

You’ll see kube-scheduler-minikube go Terminating. Now create a new pod — it’ll stay Pending:

kubectl run test-pod --image=nginx
kubectl get pod test-pod  # Status: Pending ← no scheduler!

Now restore it:

minikube ssh "sudo mv /tmp/kube-scheduler.yaml /etc/kubernetes/manifests/"
sleep 10
kubectl get pods -n kube-system  # Scheduler is back
kubectl get pod test-pod          # Now Running!
kubectl delete pod test-pod

What you learned: The Scheduler is needed for new pod placement. Existing pods are unaffected by its absence.


Cleanup

# Everything is clean — minikube cluster keeps running for future chapters
minikube status

What We Learned

#SkillVerified By
1Start and verify a K8s clusterkubectl get nodes shows Ready
2Inspect control plane podskubectl get pods -n kube-system
3Understand node resource allocationkubectl describe node minikube
4Navigate namespaceskubectl get all --all-namespaces
5Call the raw Kubernetes APIcurl localhost:8001/api/v1/namespaces
6Observe Scheduler failure impactPod stayed Pending without scheduler