Repositories: study notes and manifests in sharifndlovu123/k8s-playground (minikube, kind, kubectl, sample app, production-grade clusters) · course companion sharifndlovu123/devops-directive-kubernetes-course
Extras to go with the chapters: a working guide to running Kubernetes on your own machine. The first install walk-through is in 3. Installing Your First Kubernetes Cluster. Commands you will use daily are in kubectl Cheat Sheet.
Tools at a glance
| Tool | What it is | Good for |
|---|---|---|
| minikube | Local single or multi-node cluster in a Docker container or VM | Learning, add-ons, closest to "a real cluster on a laptop" |
| kind | Nodes as Docker containers | CI pipelines, multi-node, testing Kubernetes itself |
| k3s | Lightweight certified Kubernetes in one binary | Edge, Raspberry Pi, small servers |
| k3d | Runs k3s clusters inside Docker | Fast throwaway clusters with a built-in registry |
| MicroK8s | Canonical's snap-based Kubernetes | Ubuntu, simple add-on system |
| Docker Desktop | Single-node cluster toggle | Convenience on Windows / macOS |
| Rancher Desktop | Desktop app with k3s | Free Docker Desktop alternative |
| kubectl | The client for all of them | Everything (2. Kubernetes Architecture – from Container Images to Running Pods) |
| Helm | Package manager for Kubernetes | Installing charts (nginx, Prometheus...) |
| k9s / Lens / Headlamp | Terminal and desktop UIs | Browsing and debugging clusters |
| kubectx / kubens | Switch context and namespace fast | Multi-cluster work |
| Skaffold / Tilt | Dev loop automation | Rebuild and redeploy on code change |
flowchart TD
A[Need a local cluster] --> B{Main goal?}
B -->|Learn Kubernetes, use add-ons| C[minikube]
B -->|CI or many disposable clusters| D[kind or k3d]
B -->|Small server, edge, Raspberry Pi| E[k3s or MicroK8s]
B -->|Already on Docker Desktop| F[Enable its built-in Kubernetes]
C --> G[kubectl]
D --> G
E --> G
F --> G
minikube in Depth
minikube creates a cluster inside a driver. With the Docker driver the whole node is one container on your machine.
flowchart LR
subgraph Host[Your machine]
CLI[kubectl / minikube CLI]
subgraph D[Docker driver]
subgraph N[minikube node container]
CP[Control plane: kube-apiserver, etcd, scheduler, controller-manager]
K[kubelet + kube-proxy]
R[Container runtime: containerd / docker / CRI-O]
P[Your Pods]
end
end
end
CLI -->|HTTPS 8443 via ~/.kube/config| CP
CP --> K --> R --> P
Install and start
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ sudo install minikube-linux-amd64 /usr/local/bin/minikube
$ minikube start --driver=docker
$ minikube status
$ kubectl get nodes
Choose resources and version:
$ minikube start --cpus=4 --memory=4096 --disk-size=30g --kubernetes-version=v1.30.0
$ minikube config set driver docker # make it the default
$ minikube config set cpus 4
Drivers
| Driver | Notes |
|---|---|
docker |
Default on Linux, fastest startup, shares host kernel |
podman |
Rootless alternative |
kvm2 |
Real VM on Linux, strongest isolation |
virtualbox, vmware, hyperkit, hyperv |
VM drivers for other platforms |
none |
Runs directly on the host (needs root, avoid on a daily machine) |
Profiles (several clusters side by side)
Each profile is its own cluster and its own kubectl context.
$ minikube start -p dev
$ minikube start -p test --nodes 3
$ minikube profile list
$ minikube profile dev # set the default profile
$ minikube delete -p test
$ minikube delete --all
Stop vs pause vs delete:
| Command | Effect |
|---|---|
minikube stop |
Stops the node, keeps all state, frees CPU / RAM |
minikube pause |
Freezes Kubernetes components, node keeps running |
minikube delete |
Removes the cluster and all data |
Add-ons
Optional cluster features switched on with one command.
$ minikube addons list
$ minikube addons enable ingress
$ minikube addons enable metrics-server
$ minikube addons enable dashboard
$ minikube addons enable registry
| Add-on | Gives you |
|---|---|
ingress |
An NGINX Ingress controller for HTTP routing |
metrics-server |
Enables kubectl top pods/nodes and autoscaling |
dashboard |
Web UI (minikube dashboard) |
registry |
In-cluster image registry |
storage-provisioner |
Default StorageClass for PersistentVolumeClaims (on by default) |
csi-hostpath-driver, volumesnapshots |
CSI storage and snapshots |
Reaching your apps from the host
A Pod IP lives inside the node and is not reachable from your laptop directly. Options:
flowchart LR
U[Browser on host] -->|minikube service web --url| NP[NodePort Service]
U -->|minikube tunnel| LB[LoadBalancer Service]
U -->|kubectl port-forward| POD[Pod]
U -->|ingress add-on + host header| ING[Ingress controller] --> SVC[Service] --> POD
NP --> POD
LB --> POD
$ kubectl expose deployment web --type=NodePort --port=80
$ minikube service web --url # prints a reachable URL
$ minikube service web # opens it in the browser
$ kubectl expose deployment web --type=LoadBalancer --port=80
$ minikube tunnel # run in another terminal; assigns an external IP
$ kubectl port-forward svc/web 8080:80 # simplest for quick tests
$ minikube ip # the node's IP
minikube tunnel needs to keep running and may ask for sudo to create routes.
Using local images (no registry)
Three ways to get an image you just built into the cluster:
# 1. Point your Docker CLI at minikube's Docker daemon, then build
$ eval $(minikube docker-env)
$ docker build -t shop-api:dev .
$ eval $(minikube docker-env -u) # undo
# 2. Load an image you already built on the host
$ minikube image load shop-api:dev
$ minikube image ls
# 3. Build inside minikube
$ minikube image build -t shop-api:dev .
Then in the manifest set imagePullPolicy: IfNotPresent (or Never) so Kubernetes does not try to pull it from a registry:
containers:
- name: api
image: shop-api:dev
imagePullPolicy: IfNotPresent
Gotcha: a tag of latest defaults to imagePullPolicy: Always, which fails for local-only images.
Sharing files with the node
$ minikube mount ~/projects/site:/site # keep running; host dir appears at /site in the node
$ minikube ssh # shell into the node
$ minikube cp local.txt minikube:/tmp/local.txt
hostPath volumes refer to the node's filesystem, so mount first if you want host files.
Multi-node and version testing
$ minikube start --nodes 3 -p multi
$ kubectl get nodes
$ minikube start -p old --kubernetes-version=v1.28.0
Useful for testing scheduling, anti-affinity, taints / tolerations and rolling upgrades.
Troubleshooting
| Symptom | Try |
|---|---|
minikube start hangs or errors |
minikube delete then start again; check docker ps, free disk and RAM |
Exiting due to PROVIDER_DOCKER_NOT_RUNNING |
Start the Docker daemon and make sure your user is in the docker group |
kubectl talks to the wrong cluster |
kubectl config get-contexts, kubectl config use-context minikube |
Pod stuck ErrImagePull / ImagePullBackOff on a local image |
Use minikube image load and imagePullPolicy: IfNotPresent |
LoadBalancer EXTERNAL-IP shows <pending> |
Run minikube tunnel |
| Ingress returns 404 / no address | Enable the ingress add-on, wait for its Pod in ingress-nginx, check kubectl get ingress |
| Cluster is slow | Raise --cpus / --memory, delete unused profiles |
| Need logs | minikube logs, minikube logs --problems |
| Clean slate | minikube delete --all --purge |
kind (Kubernetes IN Docker)
Each node is a Docker container running a full kubelet, so creating and destroying clusters takes seconds. Built for testing Kubernetes and for CI.
$ kind create cluster --name demo
$ kind get clusters
$ kind load docker-image shop-api:dev --name demo # push a local image into every node
$ kind delete cluster --name demo
Multi-node with port mappings so the host can reach an Ingress:
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 80
hostPort: 8080
- containerPort: 443
hostPort: 8443
- role: worker
- role: worker
$ kind create cluster --config kind-config.yaml
Differences from minikube: no add-on system and no built-in dashboard, but real multi-node and very fast; context name is kind-<name>.
k3s and k3d
k3s is a single binary (<100 MB) that bundles a lightweight Kubernetes: SQLite instead of etcd by default, containerd, Traefik ingress, ServiceLB, CoreDNS. Ideal for Raspberry Pi and edge.
$ curl -sfL https://get.k3s.io | sh -
$ sudo k3s kubectl get nodes
$ sudo cat /etc/rancher/k3s/k3s.yaml # kubeconfig, copy to ~/.kube/config
# join an agent node:
$ curl -sfL https://get.k3s.io | K3S_URL=https://<server>:6443 K3S_TOKEN=<token> sh -
k3d wraps k3s in Docker:
$ k3d cluster create dev --servers 1 --agents 2 -p "8080:80@loadbalancer"
$ k3d cluster list
$ k3d cluster delete dev
MicroK8s, Docker Desktop and Rancher Desktop
$ sudo snap install microk8s --classic
$ microk8s status --wait-ready
$ microk8s enable dns ingress storage
$ microk8s kubectl get nodes
- Docker Desktop: Settings → Kubernetes → Enable. One node, context
docker-desktop; version is tied to the Docker Desktop release - Rancher Desktop: choose the Kubernetes version and container engine (
containerdordockerd), shipskubectlandhelm
Comparison
| minikube | kind | k3s / k3d | MicroK8s | Docker Desktop | |
|---|---|---|---|---|---|
| Start time | ~30-60 s | ~20-30 s | ~10 s | ~30 s | Part of app startup |
| Multi-node | Yes | Yes | Yes | Yes | No |
| Built-in add-ons | Many | No | Some (Traefik, ServiceLB) | Many | No |
| Dashboard | Yes | No | No | Yes | No |
| Local image workflow | image load / docker-env |
kind load |
k3d image import |
Built-in registry | Shares Docker images directly |
| Best at | Learning | CI / testing | Lightweight, edge | Ubuntu | Convenience |
Managing Contexts and Many Clusters
kubectl reads ~/.kube/config, which can hold local clusters and cloud ones (GKE, EKS, AKS) side by side. See contexts in 3. Installing Your First Kubernetes Cluster.
$ kubectl config get-contexts
$ kubectl config use-context minikube
$ kubectl config current-context
$ kubectl config set-context --current --namespace=dev
Safer habits:
- Show the context in your shell prompt
- Install kubectx and kubens to switch fast: kubectx minikube, kubens dev
- Double check the context before delete or apply against a cloud cluster
- Use separate kubeconfig files with KUBECONFIG=~/.kube/dev:~/.kube/prod kubectl config view --flatten
Helm
A package manager: a chart is a bundle of templated manifests, a release is an installed instance, a repository hosts charts.
$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo update
$ helm search repo nginx
$ helm install web bitnami/nginx --set service.type=NodePort
$ helm list
$ helm upgrade web bitnami/nginx --set replicaCount=3
$ helm rollback web 1
$ helm uninstall web
$ helm template web bitnami/nginx > rendered.yaml # see the YAML without installing
Override defaults with a values file:
# values.yaml
replicaCount: 2
service:
type: NodePort
$ helm install web bitnami/nginx -f values.yaml
Kustomize (built into kubectl -k) is the template-free alternative: a kustomization.yaml patches base manifests per environment.
$ kubectl apply -k overlays/dev
Handy UIs and Dev-loop Tools
| Tool | Notes |
|---|---|
| k9s | Terminal UI: :pods, :deploy, l logs, s shell, d describe, / filter |
| Lens | Desktop IDE for clusters |
| Headlamp | Extensible web / desktop UI |
| Kubernetes Dashboard | Official web UI (minikube dashboard) |
| stern | Tail logs from many Pods at once: stern web -n dev |
| kubectl-neat, kubectl-tree | Plugins for tidy output and object ownership trees, install with krew |
| Skaffold / Tilt | Rebuild image, redeploy, and port-forward whenever code changes |
| Telepresence | Run one service locally while it talks to the cluster |
Plugin manager:
$ kubectl krew install ctx ns neat tree
A Typical Local Workflow
sequenceDiagram
participant Dev as You
participant Docker as Docker / minikube image
participant K8s as minikube cluster
Dev->>Docker: docker build -t shop-api:dev .
Dev->>K8s: minikube image load shop-api:dev
Dev->>K8s: kubectl apply -f k8s/
K8s-->>Dev: pod/shop-api Running
Dev->>K8s: kubectl port-forward svc/shop-api 8080:80
Dev->>K8s: kubectl logs -f deploy/shop-api
Dev->>Docker: edit code, rebuild
Dev->>K8s: kubectl rollout restart deploy/shop-api
- Build the image (1. Docker)
- Load it into the cluster
- Apply manifests (4. Running Your Containers in Kubernetes)
- Reach the app (port-forward, NodePort +
minikube service, or Ingress) - Inspect, change, repeat
minikube stopwhen done,minikube deleteto reset
Compose users can compare against 2. Docker Compose; managed cloud equivalents are AKS (2. Azure Compute) and EKS (3. AWS Compute).