Scaling, and running Kubernetes in practice
🎯You'll be able to
Explain how the Horizontal Pod Autoscaler decides the number of pods, how nodes are added, and what running a cluster involves day to day.
🏠The everyday picture
A bank opens more counters when the queue grows and closes them only after the queue has stayed short for a while. If all counters are open and the queue still grows, the branch manager calls in staff from another branch.
📘What it really is
- The Horizontal Pod Autoscaler (HPA) changes a Deployment's
replicas: - desired pods = ceil(current pods × current metric ÷ target metric). With 3 pods at 90% CPU and a 60% target: ceil(3 × 90 ÷ 60) = 5;
- CPU and memory metrics come from the metrics-server; requests per second or queue length need a custom metrics adapter (for example from Prometheus, or KEDA for event-driven scaling);
- CPU percentages are relative to the pods' requests, so missing requests mean no CPU-based scaling;
minReplicasandmaxReplicasbound it, and scaling down waits for a stabilisation window (5 minutes by default) so a short dip doesn't remove pods that are needed again a moment later.-
Nodes: if new pods don't fit, they stay
Pending. The Cluster Autoscaler or Karpenter adds nodes from the cloud, and removes empty ones later. Adding a node takes minutes, so keep some headroom for sudden spikes. -
RouteRani's
tools/autoscale.js(Project 3) follows the same formula and stabilisation idea, using requests per second from Prometheus. - Running Kubernetes in practice:
- managed control plane (EKS, GKE, AKS) unless there's a strong reason not to;
- upgrades every few months, since each minor version is supported for a limited time;
- packaging: Helm charts or Kustomize to manage YAML across environments; GitOps tools (Argo CD, Flux) apply what's in Git;
- observability: Prometheus and Grafana are common (CD9);
- practice clusters: kind (Kubernetes in Docker), minikube and k3d run on a laptop.
📝A worked example
Input (not verified): an HPA for RouteRani:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: routerani-api }
spec:
scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: routerani-api }
minReplicas: 2
maxReplicas: 6
metrics:
- type: Resource
resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } }
Expected output: under load, kubectl get hpa routerani-api --watch shows the CPU percentage rising and REPLICAS growing towards 6; after
the load stops, replicas return to 2 about five minutes later, because of the stabilisation window.
🌍Where it's used
- Sale days and match days: HPAs scale web services; cluster autoscalers add nodes.
- Queue workers scale on queue length with KEDA.
- Platform teams spend much of their time on upgrades, packaging and observability, not on writing YAML.
📝Case scenario
A ticketing platform's HPA scaled pods up during a concert sale, but new pods stayed Pending for six minutes while new nodes started, and
the site slowed badly. They kept a small buffer of spare capacity (low-priority placeholder pods that real pods can push aside) and started
scaling earlier, at a lower target.
🖱️Try it
Work out the HPA formula by hand: 4 pods at 30% CPU, target 60%, minimum 2; then 2 pods at 150%, target 60%, maximum 6. Success: you get 2 (ceil(4 × 30 ÷ 60) = 2) and 5 (ceil(2 × 150 ÷ 60) = 5), and you can explain why scaling down waits.
⚠️Common mistakes
- No resource requests. Sign: the HPA shows
<unknown>for CPU. Fix: set requests; install metrics-server. - Scaling on the wrong signal. Sign: CPU stays low while a queue grows. Fix: scale on the signal that reflects the work, such as queue length or requests per second.
- No room for new nodes. Sign: pods
Pendingduring spikes. Fix: headroom, earlier scaling, or faster node provisioning.
🛠️For your project
Project 3's autoscaler uses the same formula, bounds and stabilisation window; tests 6 and 7 check it scales up to its maximum and back down to its minimum.
✅Quick check
With 2 pods at 120% CPU and a 60% target, how many pods does the HPA want?
Show the answer
ceil(2 × 120 ÷ 60) = 4.
Why does scaling down wait?
Show the answer
So a short dip doesn't remove pods that are needed again a moment later.
