Skip to content

Scale a workload from an OTel metric

Scale a non-GPU Spring Boot service from an OTLP-push metric. This walkthrough uses the existing OTel pipeline sample, pinned to commit 68ab1b012dd335db4eba70db354f2c6c62db157b. The sample routes the scaling metric to the Kedify OTel add-on while retaining a separate monitoring path.

Use a disposable local environment with Docker, k3d, Helm, kubectl, curl, jq, envsubst and hey. The setup script creates namespaces, cert-manager/trust-manager, KEDA, OTel components and sample Prometheus/Grafana. These monitoring components demonstrate fan-out; they are not required for core OTel scaling.

The pinned setup script deletes and recreates a k3d cluster named pipelines-tls. Inspect it first and use it only when that named cluster is disposable. It also discovers some chart versions dynamically and contains demo TLS verification relaxations. Record resolved chart/image versions and inspect those settings before reusing the recipe; the pinned source is a reproducible definition of the scenario, not a tested production bundle.

Terminal window
git clone https://github.com/kedify/examples.git kedify-otel-example
cd kedify-otel-example
git checkout 68ab1b012dd335db4eba70db354f2c6c62db157b
cd samples/otel-scaler-pipelines
# Review setup-springboot-push.sh, certs.yaml and springboot-push-values.yaml.
bash setup-springboot-push.sh

The script configures the Spring Boot app to push OTLP metrics over gRPC to the router collector on port 4317. The router selects http.server.request.duration for the scaler path and forwards the other metrics to the sample monitoring path. This is different from scraping the application’s Prometheus endpoint.

Verify kubectl config current-context identifies the intended demo cluster. Check deployments in app, keda and observability, and certificates with kubectl get certificates -A. Resolve failed readiness or certificate provisioning before load testing.

The pinned so-springboot-push.yaml uses an external scaler at keda-otel-scaler.keda.svc:4318, with TLS material supplied from the demo Secret. It selects:

sum(http_server_request_duration_count{http_request_method=GET,http.response_status_code=200,http_route=/ping})

operationOverTime: rate turns the counter into a request-rate signal; targetValue: "2" is the sample’s per-replica target. Preserve the actual exported label spelling from the sample. Port 4318 here is the scaler connection, not an instruction to send OTLP/HTTP there. See OTel reference for the separate query/endpoint contracts.

The sample uses minReplicaCount: 1, maxReplicaCount: 3. It tests live metric scaling, not activation from zero: a metric emitted only by stopped application pods would not be a sufficient activation source.

Terminal window
curl --fail http://localhost:8080/ping
hey -z 120s http://localhost:8080/ping
kubectl get scaledobject spring-server-push -n app -o yaml
kubectl get hpa -n app
kubectl get pods -n app -o wide
kubectl get events -n app --sort-by=.lastTimestamp

The router collector’s demo file exporter records selected scaler-path samples in /var/log/collector/keda.json. Inspect that file/log path inside the collector with authorized pod access and confirm the metric, labels and timestamps. Compare with the sample dashboard’s source rate and HPA current metric. Expect positive load to increase desired replicas, ready Spring Boot pods to follow, and requests to complete successfully. If ingestion is absent, inspect exporter/collector TLS and routing first; if the source exists but the query is empty, inspect metric names and labels.

Stop the load and observe the sample’s 60-second scale-down stabilization and eventual return toward one replica. A fixed replica increase is not guaranteed for every laptop: it depends on achieved request rate and readiness. Use workload diagnostics at the first failing layer.

Stop local port-forward/load processes. After confirming that pipelines-tls is the disposable cluster created for this tutorial, remove it with k3d cluster delete pipelines-tls. This removes its demo workloads and data; do not use the cleanup command for a shared cluster.

For an existing collector, use Choose an OTel ingestion method and OTel metric scaling to adapt the signal path. Keep existing production monitoring until the replacement or fan-out path is verified.