Lesson 9 · Scaling, scheduling & reliability
Autoscaling: HPA / VPA / KEDA
Three ways to scale — and why this repo scales consumers on Kafka lag, not CPU.
Your win: distinguish HPA (more pods), VPA (bigger pods), and KEDA (event-driven, scale-to-zero) — and explain the repo's real setup: KEDA scaling on request rate and Kafka consumer lag.
Three autoscalers, three axes
| Autoscaler | Changes | Reacts to |
|---|---|---|
| HPA (Horizontal Pod Autoscaler) | the number of Pods | a metric target, usually CPU/memory % |
| VPA (Vertical Pod Autoscaler) | each Pod's size (requests/limits) | observed usage over time |
| KEDA (Event-Driven Autoscaling) | the number of Pods, incl. to/from zero | external events: queue depth, Kafka lag, Prometheus metrics |
HPA is a control loop (Lesson 1) that adjusts a Deployment's replica count to hit a target, re-checking roughly every 15s.1 Its blind spot: it only knows resource metrics. If your bottleneck is "10,000 messages queued," CPU may look fine while you fall behind. That's what KEDA fixes.
How this repo scales — KEDA first, HPA as fallback
keda.sh/v1alpha1) is installed and .Values.keda is
set, use a KEDA ScaledObject; else if .Values.hpa is set,
use a plain HPA. The code even comments "Keda is using HPA under the hood, so we can't
also use HPA" (:52). In backend, KEDA wins — plain HPA is essentially the fallback.
Meanwhile VPA is applied to nearly everything but mostly with
updateMode: Off (_vpa.tpl:45) — it
recommends sizes without auto-applying them.
The two KEDA triggers you'll see
util.keda.requestRateScaleObject (_keda.tpl:109)
scales the main service Pods on request rate, read from a Prometheus query
over Istio's istio_requests_total metric. Defaults:
minReplicaCount 2, maxReplicaCount 8, poll every 30s, 180s cooldown
(:121-124). So traffic → more pods, quiet → fewer (down to 2).
ScaledObject targeting the -consumers Deployment (Lesson 4);
its trigger queries sum(kafka_consumergroup_lag{consumergroup="…"}) (:45) and
scales up when lag crosses a threshold — 7500 in
notificationmgmt/prod-tokyo-values.yaml. This is the textbook
KEDA use case: "messages are piling up faster than we're consuming → add consumers," which
CPU-based HPA would completely miss.
Kubernetes HPA + KEDA scaling concepts
The HPA control loop and target model, then KEDA's ScaledObject, triggers, and scale-to-zero activation phase.
→ kubernetes.io — Horizontal Pod Autoscaling
→ keda.sh — Scaling deployments (ScaledObject)
Check yourself (from memory)
Q1. HPA, VPA and KEDA respectively change…
Q2. KEDA can do what a plain HPA cannot?
Q3. This repo scales notification consumers on…
kafka_consumergroup_lag
(threshold 7500) — add consumers when messages pile up.
_app.tpl:39-56 — use KEDA
if its CRD present, else HPA ("can't use both"). Two triggers: request-rate via Prometheus
istio_requests_total (_keda.tpl:109, min 2/max 8), and
Kafka lag — notification's scaledobject-consumers.yaml on
sum(kafka_consumergroup_lag{...}), threshold 7500. VPA mostly
updateMode: Off (recommend only).