Core Concepts · Key takeaways
2 min readRapid overview
Key takeaways
- The gap KEDA fills: HPA scales only on CPU/memory and has a floor of 1 — it can't react to event sources and can't scale to zero. KEDA (CNCF graduated) adds event-driven scaling + scale-to-zero.
- Components:
keda-operator(owns 0↔1, watchesScaledObject/ScaledJob),keda-operator-metrics-apiserver(external-metrics adapter so a standard HPA reads event metrics), admission webhooks. Footprint ~50–100 Mi. - Two-phase model (the centerpiece): 0→1 (activation) is owned by the operator (the part HPA can't do; back to 0 after
cooldownPeriod, default 300s); 1→N is handed to a standard HPA KEDA creates. KEDA wraps HPA; it does not replace it. - Two thresholds per scaler: activation (0→1, operator) is distinct from target (1→N, HPA).
- ScaledObject ties a Deployment to
triggers[]and setsminReplicaCount(0 = scale-to-zero),maxReplicaCount,cooldownPeriod,pollingInterval. 60+ scalers (RabbitMQ length, Kafka lag, Prometheus query, Redis length, cron, SQS…). - HTTP needs the http-add-on because no metric exists at 0 pods: an interceptor buffers the request → signals 0→1 → waits for readiness → forwards it (and counts pending requests for 1→N), plus an external scaler and the
HTTPScaledObjectCRD. Wire the Ingress backend to the interceptor, not the app Service. Footprint ~30–60 Mi. - Cold start: first request after idle pays schedule → start → readiness (~2–5s .NET, less with ReadyToRun/AOT); the interceptor buffers it into a slow 200, not a 502. Warm requests pass straight through.
- KEDA vs HPA vs Knative: HPA = CPU/mem, min 1. KEDA = event-driven + scale-to-zero, lightweight (wraps HPA). Knative also scales to zero but its control plane (activator/autoscaler + per-pod queue-proxy sidecar) is heavy and can cost more than it saves on a tight node — so KEDA's http-add-on is preferred there.
- Consumer nuance: a consumer scaled to zero by a non-queue trigger stops draining its queue — but with the queue scaler (
rabbitmq queueLength, polled out-of-band even at 0) it sleeps at 0 and wakes on the first message, scaling 0→N on depth. So a consumer can scale to zero with the right scaler; conservative first pass isminReplicaCount: 1. - Never scale to zero: stateful workloads — databases, brokers, caches.
- What it buys: idle → 0 replicas → 0 RAM + 0 scheduling reservation, the density lever (see node-rightsizing). Caveat: 0 RAM per idle container, not a $0 hardware bill — a self-hosted node costs the same idle or full; $0-at-idle is per-request serverless only (Cloud Run/Lambda/Fly).