A hands-on monorepo to learn Kubernetes concepts by running a real application locally. It pairs with the Kubernetes Basics tutorial.
frontend/ React SPA (Vite) — served by nginx inside the cluster
backend/ Fastify API (Node.js) — the workload being orchestrated
infra/ Kubernetes manifests, one file per concept
loadtest/ autocannon load test to trigger autoscaling
Every file in infra/ is heavily commented and explains the concept it
demonstrates. Read them in this order:
| File | Concept |
|---|---|
| namespace.yaml | Namespaces |
| backend-configmap.yaml | ConfigMaps |
| backend-deployment.yaml | Deployments, probes, resources |
| backend-service.yaml | Services, DNS, NodePort |
| backend-hpa.yaml | HorizontalPodAutoscaler |
| frontend-nginx-configmap.yaml | ConfigMap as a mounted file |
| frontend-deployment.yaml | Volume mounts |
| frontend-service.yaml | Service (frontend) |
| Tool | Purpose | Install |
|---|---|---|
| Node ≥ 22 | run frontend and backend locally | nodejs.org |
| Docker | build images | docker.com |
| minikube | local Kubernetes cluster | minikube.sigs.k8s.io |
Useful for fast iteration — no cluster needed.
# backend → http://localhost:3000
cd backend && npm install && npm run dev
# frontend → http://localhost:5173 (proxies /api to localhost:3000)
cd frontend && npm install && npm run devminikube startcd infra && bash deploy.shThe script does the following on every run:
- Enables the
metrics-serveraddon (required for HPA) - Points the shell at minikube's Docker daemon so images are built inside the cluster
- Builds
backend:localandfrontend:local - Applies all manifests with
kubectl apply - Restarts both Deployments so Pods pick up the freshly built images
minikube service frontend -n app # opens the React UI in your browser
minikube service backend -n app # opens the Fastify API directlyminikube stop # pause — cluster state is preserved
minikube delete # destroy everythingShows the HPA scaling backend Pods up and down under load.
GET /api/stress?n=38 computes fib(38) recursively with no memoisation —
a deliberately CPU-intensive operation. The HPA scales up when average CPU
across all backend Pods exceeds 50% of their requested 100m.
load test → concurrent requests → CPU spikes above 50%
→ HPA adds Pods → load spreads → CPU drops → HPA removes Pods
Open a terminal and run:
while true; do clear; minikube kubectl -- get hpa,pods -n app -l app=backend; sleep 2; doneYou should see 2 backend Pods and cpu: ~1%/50% at rest.
Open a second terminal:
cd loadtest
TARGET_URL=http://$(minikube ip):30300 npm run stress
minikube ipreturns the node's IP (e.g.192.168.49.2). Port30300is the NodePort defined inbackend-service.yaml.
| Time | What happens |
|---|---|
| 0s | REPLICAS: 2, cpu: ~1%/50% |
| ~15s | CPU target climbs above 50% |
| ~30–60s | HPA adds Pods — REPLICAS grows toward 8 |
| load ends | CPU drops, Pods removed after ~30s cooldown |
Why 30–60s to scale up? metrics-server scrapes every 15s and the HPA evaluates every 15s. It needs two or three cycles before it acts.
Why is scale-down slower in production? The default stabilisation window is 300s to avoid flapping. Ours is set to 30s in
backend-hpa.yamlfor demo purposes.
| Method | Path | Description |
|---|---|---|
| GET | /health |
Readiness probe — returns { status: "ok" } |
| GET | /api/hello?name=X |
Returns { message: "Hello, X!" } |
| GET | /api/stress?n=38 |
Computes fib(n) — burns CPU to trigger the HPA |