# Scale from Ingress NGINX metrics with OTel

This guide shows how to autoscale Kubernetes workloads from metrics emitted by [ingress-nginx](https://kubernetes.github.io/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](https://github.com/kedify/examples/tree/main/samples/otel-ingress-nginx-poc).

## Architecture

[![Ingress NGINX OTel Scaler architecture](https://docs.kedify.io/assets/images/how-to/otel-scaler-ingress-nginx/diagram.svg)](https://docs.kedify.io/assets/images/how-to/otel-scaler-ingress-nginx/diagram.svg)

Scroll to exploreDiagram description

Ingress NGINX routes HTTP to the frontend, which calls the backend. A collector scrapes NGINX metrics and exports selected series over OTLP to the OTel scaler. KEDA reads the scaler over gRPC. Each workload has its own ScaledObject and query/target; KEDA and HPA or KPA update the frontend and backend Deployments independently.

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.

## Prerequisites

- 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.

The sample is intentionally small and uses a local hostname, `my-app-fe.local`. For production clusters, adapt the hostname, namespace names, chart versions, and target thresholds to your environment.

## Step 1: Run the Sample

Clone the examples repository and run the setup script:

```bash
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:

- [setup.sh](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/setup.sh)

- [apollo-values.yaml](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/apollo-values.yaml)

- [fe.yaml](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/fe.yaml)

- [otel-scaler-values.yaml](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/otel-scaler-values.yaml)

- [fe-so.yaml](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/fe-so.yaml)

- [be-so.yaml](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/be-so.yaml)

## Step 2: Enable and Scrape ingress-nginx Metrics

The sample enables the ingress-nginx controller metrics endpoint:

```bash
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:

```yaml
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:

```yaml
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:

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

See the complete [otel-scaler-values.yaml](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/otel-scaler-values.yaml) file for the full collector configuration.

## 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:

```yaml
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](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/fe-so.yaml) file.

## Step 4: Keep Backend Capacity Aligned

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

```yaml
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](https://github.com/kedify/examples/blob/main/samples/otel-ingress-nginx-poc/be-so.yaml) file.

## Step 5: Generate Load

Forward ingress-nginx locally:

```bash
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:

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

Watch the `ScaledObject`, HPA, and pods:

```bash
kubectl get scaledobject,hpa -n app
kubectl get pods -n app -w
```

You can also inspect the raw ingress-nginx metric:

```bash
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
```

## Next Steps

- Review the [Kedify OTel Scaler reference](https://docs.kedify.io/scalers/otel-scaler/) for trigger parameters and query syntax.

- Compare this pattern with other [OTel Scaler integration options](https://docs.kedify.io/how-to/otel-scaler-integrations/).

- Use the full [otel-ingress-nginx-poc sample](https://github.com/kedify/examples/tree/main/samples/otel-ingress-nginx-poc) as a starting point for adapting the collector scrape target, metric query, and thresholds.

## Continue with this topic

**Reference:** [OTel scaler configuration](https://docs.kedify.io/reference/otel-scaler/).

**Diagnose:** [Workload does not scale, or scales too slowly](https://docs.kedify.io/troubleshooting/workload-scaling/).

**Related capabilities:** [HTTP scaling](https://docs.kedify.io/scalers/http-scaler/) · [Scale using existing Envoy metrics](https://docs.kedify.io/scalers/http-envoy-scaler/).

---
Canonical: https://docs.kedify.io/how-to/otel-scaler-ingress-nginx/
Source: src/content/docs/how-to/otel-scaler-ingress-nginx.md
Documentation index: https://docs.kedify.io/llms.txt
