Scale a Kubernetes Backend from Apache APISIX Request Metrics with KEDA
August 4, 2026 ยท View on GitHub
This sample shows how to scale one Kubernetes Deployment from the request rate observed by an existing Apache APISIX gateway. APISIX exports the apisix_http_status counter, Prometheus evaluates a single-value query for one APISIX Service, and KEDA uses the result to scale the corresponding backend workload.
The example is intentionally narrow: one APISIX Service maps to one backend Deployment. Gateway request rate is a demand signal, not a measurement of backend CPU usage or work complexity.
Versions
| Component | Version |
|---|---|
| Apache APISIX | 3.17.0 |
| APISIX Helm chart | 2.16.0 |
| KEDA | 2.20.2 |
| Prometheus | 3.13.2 |
| Kubernetes | Tested version is recorded in evidence/validation-report.md |
This repository does not modify Apache APISIX. It deploys the published APISIX image and Helm chart with an opt-in, standalone runtime configuration.
Architecture
load generator
|
v
Apache APISIX -----> keda-demo-backend Service -----> backend Deployment
|
| /apisix/prometheus/metrics
v
Prometheus <------ KEDA Prometheus scaler ------> Deployment replicas
Scaling query
sum(rate(apisix_http_status{service="keda-demo"}[1m])) or vector(0)
The service matcher selects the series for one APISIX Service. sum(...) then aggregates the remaining route, status, consumer, and node label dimensions into one query result. This does not reduce the cardinality already stored by Prometheus; it keeps the value returned to KEDA unambiguous. or vector(0) keeps the result non-empty before the first request and when the selected series is absent.
The sample uses a target of 2 requests per second per replica and caps the backend at 5 replicas. These values make the behavior easy to observe in a local cluster; they are not production sizing recommendations.
The default configuration keeps minReplicaCount: 1; its 1-to-N scaling is driven by the scaler threshold and the generated HPA. activationThreshold is only exercised by the optional minReplicaCount: 0 diagnostic described below.
Prerequisites
- A disposable local
kindork3dcluster. kubectl,helm,curl, andjq.- At least 4 CPUs and 6 GiB of memory available to the cluster runtime.
- Network access to pull the pinned images and Helm charts.
The scripts reject non-local Kubernetes contexts unless ALLOW_NON_LOCAL_CLUSTER=1 is explicitly set.
Run the sample
./scripts/run-demo.sh
./scripts/verify-scaling.sh
The verification script checks the initial replica count, the Prometheus result shape, scale-up under load, and scale-down after load stops. It also records KEDA conditions and HTTP failures observed while scaling.
To generate or stop traffic manually:
./scripts/generate-load.sh start
./scripts/generate-load.sh status
./scripts/generate-load.sh stop
Scale-to-zero boundary
The validated default keeps one backend replica. This request-completion metric is not a reliable activation signal when the backend is already at zero: APISIX records apisix_http_status after a request completes, while requests can wait for an unavailable upstream. In the local boundary test, the metric stayed below the 0.5 activation threshold long enough to prevent a dependable cold start.
The diagnostic manifest is retained only to reproduce that limitation:
RUN_SCALE_TO_ZERO=1 ./scripts/verify-scaling.sh
This diagnostic may time out by design. In the recorded run, clients observed timeouts and APISIX recorded 499 and 502 responses. The sample therefore uses minReplicaCount: 1 and does not present scale-to-zero as supported behavior.
The verification script restores the default ScaledObject when it exits or is interrupted. To restore it manually after any diagnostic run:
kubectl apply -f manifests/scaledobject.yaml
Failure-path check
To include a temporary Prometheus outage in the verification:
RUN_FAILURE_TESTS=1 ./scripts/verify-scaling.sh
The script restores Prometheus before it exits. With ignoreNullValues: "false", KEDA should surface the failed query instead of silently treating the missing target as an empty metric.
Cleanup
./scripts/cleanup.sh
This removes the demo namespace. Set REMOVE_KEDA=1 to also uninstall the KEDA Helm release used by the sample.
Scope and limitations
- The sample scales only the backend
Deployment; it does not scale APISIX. - It does not claim that request rate measures backend saturation.
- It does not provide capacity recommendations or benchmark results.
- The PromQL must remain scoped to exactly one backend workload.
- Production deployments should derive thresholds from application SLOs, capacity tests, queueing behavior, and cold-start tolerance.
Maintenance
Maintainer: Yilia Lin, Apache APISIX Committer.
The sample will be re-tested when the KEDA Prometheus scaler API, APISIX metric labels, or pinned major versions change.
License
Apache License 2.0. See LICENSE.