Skip to content

For the complete documentation index and AI-optimized content, see /llms.txt. All pages support markdown format via .md extension or Accept: text/markdown header.

Scale Ingress NGINX Workloads with OTel

For the complete documentation index and AI-optimized content, see /llms.txt. All pages support markdown format via .md extension or Accept: text/markdown header.

This guide shows how to autoscale Kubernetes workloads from metrics emitted by ingress-nginx and scraped by OpenTelemetry Collector. It is useful when ingress-nginx already observes the traffic you want to scale on, and you want KEDA to react to that signal without routing traffic through the Kedify HTTP proxy.

The complete runnable sample is available in the Kedify examples repository: samples/otel-ingress-nginx-poc.

Ingress NGINX OTel Scaler architecture

The sample uses this flow:

  • traffic reaches the frontend through ingress-nginx
  • ingress-nginx exposes Prometheus-style controller metrics
  • OpenTelemetry Collector scrapes ingress-nginx-controller-metrics.ingress-nginx.svc:10254
  • the collector filters the metric stream down to the ingress-nginx metric used for scaling
  • Kedify OTel Scaler receives that metric over OTLP/gRPC
  • KEDA reconciles the ScaledObject resources and scales the frontend and backend workloads

The frontend ScaledObject scales from an ingress-nginx metric. The backend ScaledObject uses the kubernetes-workload scaler so the backend can follow frontend demand.

  • A Kubernetes cluster with KEDA and Kedify installed.
  • kubectl, helm, and hey installed locally.
  • ingress-nginx installed or installable in the cluster.
  • ingress-nginx controller metrics enabled.

Clone the examples repository and run the setup script:

Terminal window
git clone https://github.com/kedify/examples.git
cd examples/samples/otel-ingress-nginx-poc
./setup.sh

The setup script installs the sample Apollo Router backend, enables ingress-nginx metrics, installs the OTel add-on, and applies the frontend and ScaledObject manifests.

Relevant files:

Step 2: Enable and Scrape ingress-nginx Metrics

Section titled “Step 2: Enable and Scrape ingress-nginx Metrics”

The sample enables the ingress-nginx controller metrics endpoint:

Terminal window
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update ingress-nginx
helm upgrade -i ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.metrics.enabled=true

If ingress-nginx is already installed with custom values, include those values or --reuse-values when enabling metrics.

The OTel add-on values then configure OpenTelemetry Collector to scrape that endpoint:

otelCollector:
enabled: true
alternateConfig:
receivers:
prometheus:
config:
scrape_configs:
- job_name: "otelcol"
scrape_interval: 5s
static_configs:
- targets:
["ingress-nginx-controller-metrics.ingress-nginx.svc:10254"]

The sample filters the metric stream before sending it to Kedify OTel Scaler:

processors:
filter/ottl:
error_mode: ignore
metrics:
metric:
- |
name != "nginx_ingress_controller_connect_duration_seconds"

The exporter sends metrics to the OTel scaler OTLP endpoint:

exporters:
otlp/keda:
endpoint: keda-otel-scaler.keda.svc:4317
compression: "none"
tls:
insecure: true

See the complete otel-scaler-values.yaml file for the full collector configuration.

Step 3: Scale the Frontend from ingress-nginx Metrics

Section titled “Step 3: Scale the Frontend from ingress-nginx Metrics”

The frontend ScaledObject uses the kedify-otel trigger and queries the metric for the frontend service in the app namespace:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: my-app-fe-so
namespace: app
spec:
scaleTargetRef:
name: my-app-fe
triggers:
- type: kedify-otel
metadata:
scalerAddress: "keda-otel-scaler.keda.svc:4318"
metricQuery: "nginx_ingress_controller_connect_duration_seconds_count{service=my-app-fe,namespace=app}"
operationOverTime: "rate"
targetValue: "1000"
minReplicaCount: 1
maxReplicaCount: 4

operationOverTime: "rate" turns the ingress-nginx counter into a rate-like signal for autoscaling. The sample target is intentionally simple; tune targetValue, stabilization windows, and replica limits for your own traffic pattern.

See the complete fe-so.yaml file.

The backend ScaledObject in the sample uses kubernetes-workload to scale the Apollo Router backend from the number of frontend pods:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: my-app-be
namespace: app
spec:
scaleTargetRef:
name: my-app-be
triggers:
- type: kubernetes-workload
metadata:
podSelector: "app=my-app-fe"
value: "1"
minReplicaCount: 1
maxReplicaCount: 4

This keeps backend capacity coupled to the frontend instead of duplicating the ingress-nginx metric query. See the complete be-so.yaml file.

Forward ingress-nginx locally:

Terminal window
kubectl port-forward -n ingress-nginx service/ingress-nginx-controller 8080:80

In another terminal, send traffic using the host configured in the sample Ingress:

Terminal window
hey -c 100 -z 60s -t 90 -host my-app-fe.local http://localhost:8080

Watch the ScaledObject, HPA, and pods:

Terminal window
kubectl get scaledobject,hpa -n app
kubectl get pods -n app -w

You can also inspect the raw ingress-nginx metric:

Terminal window
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller-metrics 10254:10254
curl -s http://localhost:10254/metrics | grep nginx_ingress_controller_connect_duration_seconds_count