Part 2 of a 4-part series — this article covers the repo at tag v2.0-load-testing-autoscaling. Part 1 (EKS deployment, tag v1.0-eks-deployment) is here.
The Setup
Last build: Google's Online Boutique running on a fixed 2-node AWS EKS cluster — 11 services, one Helm release, no autoscaling. The question this time: what actually happens under load? Not "the YAML looks right" — actually driven, actually watched, actually proven.
The Build
Two changes to the cluster from the last video:
kubernetes-manifests-aws/
├── hpa/ → HorizontalPodAutoscaler for 10 services, CPU + memory targets
└── metrics-server/ → the add-on HPA depends on — verified running first
karpenter/
├── nodepool.yaml → replaces the fixed-size node group
└── ec2nodeclass.yaml → instance requirements Karpenter provisions against
metrics-server is the dependency almost nobody checks first. HPA reads CPU/memory percentages from it — if it's not running, kubectl get hpa just shows <unknown> targets forever, silently. First command in this build: kubectl get deployment metrics-server -n kube-system.
The Load Test
k6 runs in-cluster, ramping virtual users directly against the storefront's internal service address — no external load balancer bottleneck skewing the numbers. The test script targets 100,000 VUs at full scale; for this recorded run it's scaled down to 3,000 VUs, stated openly rather than glossed over, to keep the run inside what this AWS account's free-tier-eligible node ceiling can actually absorb.
kubectl apply -f k6-load-test.yaml
kubectl get pods -n load-testing -w
Watching HPA Respond
kubectl get hpa -n online-boutique -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
frontend Deployment/frontend 45%/60%, 210Mi 2 10 2
cartservice Deployment/cartservice 78%/60%, 340Mi 2 10 4
checkoutservice Deployment/checkoutservice 82%/60%, 290Mi 2 10 5
REPLICAS climbs live as CPU/memory cross the target threshold — not a static config, an observed response to the k6 traffic actually landing on these pods.
Watching Karpenter Respond
kubectl get nodes -w
Node count climbs from 2 to 8 as HPA's new replicas outgrow what the original 2 nodes can schedule. Karpenter watches for Pending pods, picks an instance type from the EC2NodeClass constraints, and provisions a new node — no fixed node group ceiling to hit.
kubectl get nodepool,ec2nodeclass
The moment a Pending pod's node comes Ready, the scheduler places it immediately — that transition, pod snapping onto a freshly-provisioned node, is the single clearest proof autoscaling is actually working end to end.
The Dashboard
Grafana at /d/online-boutique-autoscaling plots HPA replica counts, node counts, and CPU/memory per service on one screen — every panel trending upward together during the ramp, and back down together once k6 finishes and Karpenter consolidates idle nodes away.
The Result
kubectl get hpa -n online-boutique
10 services scaled, REPLICAS up across the board.
kubectl get nodes
8 Ready nodes at peak, back to 2 within minutes of load testing stopping — Karpenter's consolidation reclaiming capacity nobody's using anymore.
What I Learned
1. Verify metrics-server before trusting HPA at all.
An HPA with no metrics source doesn't error loudly — it just sits at <unknown> targets and never scales. Check the dependency first, every time.
2. Karpenter removes the node-group ceiling, not the need to think about limits.
No fixed max-node count means no silent capacity wall — but EC2NodeClass constraints (instance types, AZs) still need to match what the account is actually allowed to provision.
3. A load test is worth nothing until you've watched it end to end.
HPA config and a NodePool definition sitting in a repo prove nothing on their own. Watching REPLICAS and node count actually climb under generated traffic is the only real verification.
4. State the scale-down honestly.
3,000 VUs, not the full 100,000-VU script — said on camera, not hidden. Same honesty standard as marking ALB "provisioned, not installed" in the first build: every claim matches what the repo and the run actually did.
Try It
GitHub (this video's exact state): https://github.com/ThinkWithOps/thinkwithops-online-boutique-production/tree/v2.0-load-testing-autoscaling
Demo walkthrough: https://youtu.be/mjGCdLFqZ7k
Tag: v2.0-load-testing-autoscaling
git checkout v2.0-load-testing-autoscaling
kubectl apply -f kubernetes-manifests-aws/hpa/
kubectl apply -f karpenter/
kubectl apply -f k6-load-test.yaml
kubectl get hpa,nodes -w
What's your default — Karpenter or Cluster Autoscaler — for EKS in 2026? Curious what other teams have landed on.
Top comments (0)