|
| 1 | +## `OTEL <--> KEDA` add-on |
| 2 | + |
| 3 | +[](https://artifacthub.io/packages/search?repo=otel-add-on) |
| 4 | + |
| 5 | +### Description |
| 6 | + |
| 7 | +This is an external scaler for KEDA that intergrates with OpenTelemetry (OTEL) collector. The helm chart deploys also OTEL |
| 8 | +collector (using the [upstream helm chart](https://github.com/open-telemetry/opentelemetry-helm-charts)) where one can set up |
| 9 | +filtering so that scaler receives only those metrics that are needed for scaling decisions |
| 10 | +([example](https://github.com/kedify/otel-add-on/blob/v0.0.0-1/helmchart/otel-add-on/values.yaml#L133-L147)). |
| 11 | + |
| 12 | +The application consist of three parts: |
| 13 | +- receiver |
| 14 | +- simple metric storage |
| 15 | +- scaler |
| 16 | + |
| 17 | +#### Receiver |
| 18 | + |
| 19 | +This component is implementation of OTLP Receiver [spec](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/opencensusreceiver), |
| 20 | +so that it spawns a GRPC server ([by default](https://github.com/kedify/otel-add-on/blob/v0.0.0-1/helmchart/otel-add-on/values.yaml#L60) on port `4317`) |
| 21 | +and stores all incoming metrics in the short term storage - simple metric storage. |
| 22 | + |
| 23 | +#### Simple Metric Storage |
| 24 | + |
| 25 | +Very simple metric storage designed to remember last couple of measurements (~ 10-100) for each metric vector. It can be |
| 26 | +[configured](https://github.com/kedify/otel-add-on/blob/v0.0.0-1/helmchart/otel-add-on/values.yaml#L11-L12) |
| 27 | +with number of seconds to remember. Then during the write operation, it removes the stale measurements, so it effectively works as a |
| 28 | +cyclic buffer. Metrics are stored together with labels (key-value pairs) for later querying. |
| 29 | + |
| 30 | +#### External Scaler |
| 31 | + |
| 32 | +This component also spawns GRPC server ([by default](https://github.com/kedify/otel-add-on/blob/v0.0.0-1/helmchart/otel-add-on/values.yaml#L61) on port `4318`) |
| 33 | +and can talk to KEDA operator by implementing the External Scaler [contract](https://keda.sh/docs/2.15/concepts/external-scalers/). |
| 34 | + |
| 35 | +It queries the internal in-memory metric storage for metric value and sends it to KEDA operator. The metric query is specified as a metadata on KEDA's |
| 36 | +ScaledObject CR, and it provides a limited subset of features as PromQL. |
| 37 | + |
| 38 | +### Architecture |
| 39 | + |
| 40 | +- ([diagram link](https://excalidraw.com/#json=P5ptHj7eQHF3qpCyDDehT,gVJvYLtm0qVR2sStjUlapA)) |
| 41 | +- [1] [OTLP format](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc) |
| 42 | +- [2] [OTLP metric receiver](https://github.com/open-telemetry/opentelemetry-collector/blob/d17559b6e89a6f97b6800a6538bbf82430d94678/receiver/otlpreceiver/otlp.go#L101) |
| 43 | +- [3] [processors](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor) |
| 44 | +- [4] https://opencensus.io - obsolete, will be replaced by OTEL |
| 45 | +- [5] [OpenCensus receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/opencensusreceiver) |
| 46 | +- [6] [Prometheus receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/prometheusreceiver) |
| 47 | +- [7] [OTLP exporter](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/otlpexporter/README.md) |
| 48 | + |
| 49 | +### Example use-cases |
| 50 | + |
| 51 | +#### 1. convert and react on metrics from OpenCensus |
| 52 | + |
| 53 | +By specifying an [opencensus receiver](https://github.com/kedify/otel-add-on/blob/v0.0.0-1/helmchart/otel-add-on/values.yaml#L112) in the helm chart values for OTEL collector, |
| 54 | +we will get the ability to get those metrics into our scaler. |
| 55 | + |
| 56 | +#### 2. convert and react on metrics from any other upstream receiver |
| 57 | +OTEL collector contains [numerous](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver) integrations on the receiver part. |
| 58 | +All of these various receivers open new ways of how to turn metric from OTEL receiver into KEDA scaler. For instance by using |
| 59 | +[sqlqueryreceiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/sqlqueryreceiver), one can achieve similar goals as with |
| 60 | +[MySQL](https://keda.sh/docs/2.15/scalers/mysql/) or [PostgreSQL](https://keda.sh/docs/2.15/scalers/postgresql/) scalers. |
| 61 | +By using [githubreceiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/githubreceiver), one can hook to |
| 62 | +metrics from GitBub, etc. |
| 63 | + |
| 64 | +#### 3. process the metrics before reaching the scaler |
| 65 | +OTEL collector provides [various processors](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor) |
| 66 | +that are being applied on all incoming metrics/spans/traces and one achieve for instance metric [filtering](https://github.com/kedify/otel-add-on/blob/v0.0.0-1/helmchart/otel-add-on/values.yaml#L138-L143) |
| 67 | +this way. So that not all the metric data are passed to scaler's short term memory. This way we can keep the OTEL scaler pretty lightweight. |
| 68 | + |
| 69 | +OTTL lang: |
| 70 | +- [spec](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/LANGUAGE.md) |
| 71 | +- [functions](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/ottl/ottlfuncs) |
| 72 | + |
| 73 | +If the simple metric query is not enough and one requires to combine multiple metric vectors into one or perform simple |
| 74 | +arithmetic operations on the metrics, there is the [Metrics Generation Processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/metricsgenerationprocessor) |
| 75 | +available as an option |
| 76 | + |
| 77 | +#### 4. OTEL patterns (metric pipelines) |
| 78 | +Basically any scenario described in [OTEL patterns](https://github.com/jpkrohling/opentelemetry-collector-deployment-patterns) or [architecture](https://opentelemetry.io/docs/collector/architecture/) |
| 79 | +should be supported. So no matter how the OTEL collectors are deployed, whether it's a fleet of sidecar containers deployed alongside each workload or |
| 80 | +some complex pipeline that spans multiple Kubernetes clusters, you will be covered. |
| 81 | + |
| 82 | +## Installation |
| 83 | + |
| 84 | +### First install KEDA |
| 85 | +```bash |
| 86 | +helm repo add kedacore https://kedacore.github.io/charts |
| 87 | +helm repo update |
| 88 | +helm upgrade -i keda kedacore/keda --namespace keda --create-namespace |
| 89 | +``` |
| 90 | + |
| 91 | +### Then install this add-on |
| 92 | +```bash |
| 93 | +helm upgrade -i kedify-otel oci://ghcr.io/kedify/charts/otel-add-on --version=v0.0.5 |
| 94 | +``` |
| 95 | + |
| 96 | +### Create an example scaled object |
| 97 | +```bash |
| 98 | +k apply -f examples/so.yaml |
| 99 | +``` |
| 100 | + |
| 101 | +## Troubleshooting |
| 102 | + |
| 103 | +To figure out the actual value of a metric query, there is a simple REST api that can be used: |
| 104 | + |
| 105 | +```bash |
| 106 | +(kubectl port-forward svc/keda-otel-scaler 9090&) |
| 107 | +# swagger doc: http://localhost:9090/swagger/index.html |
| 108 | +# test the existing metric query |
| 109 | +curl -X 'POST' \ |
| 110 | + 'http://localhost:9090/memstore/query' \ |
| 111 | + -H 'accept: application/json' \ |
| 112 | + -H 'Content-Type: application/json' \ |
| 113 | + -d '{ |
| 114 | + "operationOverTime": "last_one", |
| 115 | + "query": "kube_deployment_status_replicas_available{deployment=foo,namespace=observability}" |
| 116 | +}' |
| 117 | +{ |
| 118 | + "ok": true, |
| 119 | + "operation": "query", |
| 120 | + "error": "", |
| 121 | + "value": 1 |
| 122 | +} |
| 123 | + |
| 124 | +# check the data if the labels are stored there correctly: |
| 125 | +curl -X 'GET' \ |
| 126 | + 'http://localhost:9090/memstore/data' \ |
| 127 | + -H 'accept: application/json' | jq '.kube_deployment_status_replicas_available[].labels' |
| 128 | +{ |
| 129 | + "deployment": "keda-operator", |
| 130 | + "namespace": "keda" |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +### Configuration for OTEL collector |
| 135 | + |
| 136 | +This repo has the OTEL collector helm chart as a dependency and some issues in the configuration are guarded |
| 137 | +by their upstream JSON Schema, but some are not, and it's a good idea to run the validator (especially if it's part |
| 138 | +of a CI/CD pipeline): |
| 139 | + |
| 140 | +``` |
| 141 | +# 1) download the binary |
| 142 | +VERSION=0.117.0 |
| 143 | +curl -sL https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${VERSION}/otelcol-contrib_${VERSION}_$(go env GOOS)_$(go env GOARCH).tar.gz | tar xvz - -C . |
| 144 | +
|
| 145 | +# 2) run the validator against your helm chart values |
| 146 | +./otel-contrib validate --config=<(cat values.yaml | yq '.opentelemetry-collector.alternateConfig') |
| 147 | +``` |
| 148 | + |
| 149 | +Alternatively, you may want to use online tools such as [otelbin.io](https://www.otelbin.io/). |
0 commit comments