Overview: KEDA Scale to Zero
KEDA (Kubernetes Event-Driven Autoscaling) can reduce the replica count of workloads (Deployment / StatefulSet, etc.) down to 0 when trigger conditions are not met, saving resources; when events reappear, it scales up automatically. This enhances native HPA: vanilla HPA only works when minReplicas >= 1, while KEDA, driven by external events and maintaining its own HPA, enables “event-aware standby with 0 replicas”.
How it works (high-level flow)
- You deploy your workload (e.g.,
Deployment keda-test) and may set the initial replicas to 0. - Create a
ScaledObject(orScaledJob) describing:- Target (
scaleTargetRef.name) - Triggers (
triggers) - Scaling policies (min/max, desired replicas, etc.)
- Target (
- The KEDA Operator periodically (
pollingInterval) polls or pulls events/metrics from the trigger backend. - When the trigger condition is satisfied:
- If current replicas < desired, KEDA creates/updates a dedicated HPA (typically named
<deploymentName>-<hash>), and that HPA pushes replicas up to the target (or adjusts within the range).
- If current replicas < desired, KEDA creates/updates a dedicated HPA (typically named
- When events disappear:
- After waiting for
cooldownPeriod(and no new events during that time), KEDA scales the replicas down tominReplicaCount; if it is 0, it completely stops the Pods.
- After waiting for
Key fields (ScaledObject.spec)
| Field | Purpose | Notes |
|---|---|---|
scaleTargetRef.name | The workload name to bind | Must match the Deployment name |
pollingInterval | Polling frequency for triggers (seconds) | Default 30s; lower is more responsive but costs more resources |
cooldownPeriod | Seconds to wait before scaling down after triggers stop | Helps avoid flapping |
minReplicaCount | Minimum replicas | Set to 0 to truly “scale to zero” |
maxReplicaCount | Maximum replicas | Upper bound of resource usage |
triggers[].type | Trigger type | e.g., cron, cpu, prometheus, kafka, rabbitmq, etc. |
triggers[].metadata | Trigger-specific parameters | Vary by type |
Note: If
minReplicaCountis not explicitly set, some triggers default to 0 while some versions may default to 1. It’s recommended to explicitly set it to 0 to avoid inconsistent behavior.
Relationship with HPA
KEDA creates and manages a “bridge HPA”:
- Scale up: HPA increases replicas based on metrics injected by KEDA (
External/Objectmetrics). - Scale to 0: When metrics vanish and
cooldownPeriodelapses, KEDA directly patches the target object’s replicas to 0 (HPA itself won’t proactively set 0).
The Cron trigger in this example
scaledobject.yaml:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: keda-cron-scaledobject
spec:
scaleTargetRef:
name: keda-test
pollingInterval: 15 # check every 15 seconds
cooldownPeriod: 30 # wait 30 seconds before scaling down after window ends
minReplicaCount: 0
maxReplicaCount: 2
triggers:
- type: cron
metadata:
timezone: Asia/Shanghai
start: "0 * * * *" # start at second 0 each minute, desired replicas = 1
end: "30 * * * *" # stop at second 30 each minute
desiredReplicas: "1"Timeline (taking minute 12:00 as an example):
- 12:00:00 ~ 12:00:30: trigger active, replicas go to 1 (if previously 0).
- 12:00:30: trigger window ends,
cooldownPeriodstarts. - 12:01:00: 30-second cooldown completes (no new window during it), replicas drop back to 0.
- 12:01:00 is also the next minute’s start → scales up again (may see 0→1 flapping).
Ways to avoid repeated oscillation at window boundaries:
- Set
cooldownPeriodto match your start interval and overlap strategy (e.g., shorter than the gap). - Adjust cron expressions so the end isn’t tight to the next start boundary (e.g., set end to
55 * * * *for a wider window).
Scale-to-zero support across common triggers
Supported: cron, prometheus (when metric becomes 0 with no load), Kafka / RabbitMQ / Azure Queue / Redis Streams / NATS / PostgreSQL-Lag, and most event-driven triggers. Notes:
- CPU/memory (native HPA metrics) alone cannot scale to 0 (no metrics when Pod=0). You need external events or a custom metric that reflects “need ≥1 replica”.
- For HTTP traffic, use the KEDA HTTP Add-on or a gateway/queue-based wake-up approach.
Cold start and optimizations
When scaling from 0 to 1:
- Image pull (if not cached)
- Container start & application initialization
- Readiness probe passes (if configured)
Optimizations:
- Use smaller images / pre-pull images (e.g., DaemonSet prewarming).
- Shorten application startup path (lazy init where possible).
- For ultra-low latency endpoints, keep a small always-on instance (
minReplicaCount: 1) and split other tasks out.
Troubleshooting tips
- Check ScaledObject status:bashLook at
kubectl get scaledobject keda-cron-scaledobject -o yamlstatus.conditionsandstatus.scaleTargetKind. - Inspect KEDA operator logs:bash
kubectl logs -n keda -l app=keda-operator - Inspect generated HPA:bash
kubectl get hpa -A | findstr keda-test - Confirm Deployment replicas:bash
kubectl get deploy keda-test -o wide - If not scaling down: still in cooldown? any residual events? is
minReplicaCountset to 0?
FAQ
| Question | Likely cause | Fix |
|---|---|---|
| Never scales up | Cron time not reached / timezone mismatch | Verify timezone and current cluster time (date -u) |
| Won’t scale to 0 | minReplicaCount not 0 / cooldown not finished / events still present | Check fields and logs |
| Flapping at boundaries | start/end overlaps with cooldown | Adjust window or cooldown |
| Cold start too slow | Large image / heavy init | Prewarm, split, slim down |
Best practices at a glance
- Explicitly set
minReplicaCount: 0and a reasonablemaxReplicaCount. - Use a “boolean event” type trigger to represent “need at least 1 replica”, rather than CPU metrics alone.
- Tune
pollingIntervalandcooldownPeriodto balance responsiveness and stability. - Monitor startup latency in production; split out a lightweight always-on service if needed.
- Create a regression script to regularly validate: idle → inject event → first-request latency meets SLO.
Summary
KEDA scale-to-zero = event-driven + self-managed HPA + explicit minimum replicas of 0. Master the three core parameters (minReplicaCount / pollingInterval / cooldownPeriod) and the characteristics of your triggers to run event-driven workloads safely, elastically, and economically.