§12 keda http
Source: examples/12-keda-http/ · ← Back to examples index
Demonstrates KEDA’s HTTP add-on (BETA) — scale-from-zero on HTTP request traffic. Same workload as §6 (nginx-custom:v1), now autoscaled based on in-flight request concurrency.
Pre-requisites
./scripts/setup-keda.sh # installs both KEDA core + HTTP add-on
The HTTP add-on installs alongside KEDA core in the keda
namespace — setup-keda.sh does both. The demo also needs the
minikube profile created with the core published ports
(CORE_PORTS in scripts/lib/_helpers.sh, §4): nodePort 30080
is published as 127.0.0.1:18080. No Strimzi needed for
this demo (Kafka demo is independent — see
examples/12-keda-kafka/).
What this tests
Six §12 HTTP claims:
- KEDA HTTP add-on installs cleanly via helm at the pinned
version (0.16.0) on the existing
minikubeprofile - An
HTTPScaledObjectCR + a Deployment withreplicas: 0results in zero replicas at idle - The HTTP add-on interceptor buffers the first request during cold-start instead of returning 5xx — the client waits a few seconds but ultimately gets a 200
- Sustained HTTP load via
hey -n 500 -c 50causes KEDA to scale the nginx Deployment up (typically to 5 replicas, capped byreplicas.max: 5) - The load test completes successfully (no failed requests)
- After
scaledownPeriod(30s) of zero traffic, KEDA scales back to zero replicas
Running
./demo.sh
Expected timing:
- First run (if nginx-custom:v1 needs to build): ~2-3 min
- Subsequent runs: ~90-150 seconds
What you’ll see
✓ KEDA + HTTP add-on present in 'keda' namespace
✓ nginx-custom:v1 available
✓ manifests applied
✓ nginx at 0 replicas ← scale-to-zero
✓ interceptor reachable
✓ cold-start succeeded (HTML response received after Ns)
✓ nginx scaled up — peak replicas: N ← scale up
✓ nginx back at 0 replicas ← scale down
✓ SUCCESS
The cold-start time is the interesting metric. The HTTP add-on
interceptor receives the first request, signals KEDA, waits for
the Pod to be Ready, then forwards the request. Typical
cold-start: 3-8 seconds on this minikube setup (image cached,
Pod startup dominated by readinessProbe initialDelaySeconds).
When this fails
- All hey requests return 404 (most common gotcha) — caused
by using
-H 'Host: nginx.local'instead of-host nginx.local. hey is written in Go; Go’snet/httpsilently strips Host headers set via the headers map (issue golang/go#7682, open since 2014). The dedicated-hostflag works because hey sets Go’s specialRequest.Hostfield directly. Always use-hostwith hey when targeting virtual-host-based proxies. curl handles-H 'Host:'correctly because curl treats Host as a special case heynot installed —go install github.com/rakyll/hey@v0.1.5per §2- HTTP add-on not installed — symptom: pre-flight
complains about
keda-add-ons-http-interceptornot found../scripts/setup-keda.shinstalls both core + add-on - Cold-start timeout — if the interceptor’s first request
takes >60s, something’s wrong with the Pod startup. A configured
timeout (
interceptor.readinessTimeout, default disabled in 0.16) surfaces as HTTP 504, not 502. Checkkubectl describe pod -l app=nginx-httpfor events - Scale-up doesn’t happen — the HTTPScaledObject CRD has
a status block;
kubectl describe httpscaledobjectshows conditions. The demo dumps this on failure - nodePort 30080 is already taken, or not published —
§6, §8, §9 and this demo share nodePort 30080 and only one
holds it at a time. The demo fails with
delete <ns>/<svc> firstwhen another Service owns it; delete that Service (or run itscleanup.sh) and re-run. If the profile was created without127.0.0.1:18080:30080, the demo prints the exactminikube deleteandminikube startcommand with the full port map; published ports are fixed at profile creation Host: nginx.localheader missing — the interceptor routes based on the Host header. The demo always sets it; if you’re testing manually,curl -H 'Host: nginx.local' http://127.0.0.1:18080/is the recipe
Host access
The interceptor Service the chart installs
(keda-add-ons-http-interceptor-proxy) is ClusterIP and is never
patched, because helm upgrade would revert it. The demo applies a
companion Service this repo owns,
host-access/interceptor-host.yaml (keda-interceptor-host in
namespace keda, NodePort 30080, selecting the same interceptor
Pods). The minikube profile publishes that nodePort, so
requests go to http://127.0.0.1:18080/ with a
Host: nginx.local header. No helper process is involved,
so nothing disconnects mid-run. The companion lives outside
manifests/ and is applied only for the length of the demo.
Cleanup
Cleanup trap removes the Deployment, Service,
HTTPScaledObject, and the keda-interceptor-host companion
(freeing nodePort 30080 for §6, §8, §9). KEDA stays installed
(re-install is slow).
For deeper cleanup, use cleanup.sh:
# Remove the nginx workload + HTTPScaledObject + interceptor-host
# (keeps KEDA
# installed for next time)
./cleanup.sh
# Also remove KEDA + HTTP add-on
./cleanup.sh --remove-operators
Note: --remove-operators removes BOTH KEDA core and the HTTP
add-on, which also affects the §12 Kafka demo (since it depends
on KEDA too). To remove only the HTTP add-on while keeping KEDA
core for the Kafka demo:
helm uninstall keda-add-ons-http -n keda
Going further on your own
- Try
scalingMetric.rateinstead ofconcurrency. Rate is requests-per-second over a window; concurrency is in-flight requests at a moment. Different shapes for different workloads - Bump
replicas.maxand re-runhey -c 200. With more concurrent clients, you’ll see more replicas spin up (until you hit your minikube resource limits) - Watch the interceptor logs during a cold-start —
kubectl logs -n keda deployment/keda-add-ons-http-interceptor -f. The interceptor logs its queue state and scaling decisions - Combine with the Kafka pattern — production workloads often need both: HTTP request scaling for the front-end, Kafka lag scaling for the consumers. KEDA handles both models simultaneously on the same cluster
- Production readiness: the HTTP add-on is officially in BETA. For production HTTP autoscaling, look at knative, Kedify’s commercial HTTP Scaler, or wait for the add-on’s GA release. KEDA core is GA and production-grade