Cover image for LiveWyer blog post: Getting Started with Autoscaling in Kubernetes with KEDA
Engineering β€’ 11min read

Getting Started with Autoscaling in Kubernetes with KEDA

Considering using KEDA for autoscaling? Understanding these KEDA features and concepts may help you

Written by:

Avatar Kenny Vu Kenny Vu

Published on:

Jun 2, 2025

Last updated on:

Jun 9, 2025

This blog is part of our KEDA series, we recommend reading the rest of the posts in the series:

  1. Introducing Kubernetes Event-driven Autoscaling (KEDA)
  2. Getting Started with Autoscaling in Kubernetes with KEDA
  3. Autoscaling workloads with KEDA and the Prometheus Scaler

Installing KEDA

The official Kubernetes Event-driven Autoscaling (KEDA) documentation provides several different options that can be used to deploy KEDA to a Kubernetes cluster. As a prerequisite, it’s important to verify the Kubernetes version compatibility in the documentation: at the time of writing, KEDA requires Kubernetes v1.29 or higher:

kubectl version

If your cluster meets the version requirement, you can install KEDA using one of the officially documented methods. For example, to install KEDA using the Helm chart, you can run the following commands:

helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --version 2.17.1 \
  --create-namespace --namespace keda --wait

Once installed, you will find pods similar to the ones below in your cluster.

$ kubectl get pods -n keda
NAME                                               READY   STATUS    RESTARTS   AGE
keda-admission-webhooks-657667f97d-7dttb           1/1     Running   0          34s
keda-operator-887598c9b-tfmwj                      1/1     Running   0          34s
keda-operator-metrics-apiserver-7f5d6df58b-lzqrx   1/1     Running   0          34s

You may notice that there is a keda-operator-metrics-apiserver Deployment and if you run:

kubectl describe deployment keda-operator-metrics-apiserver -n keda

You will find:

...
   keda-operator-metrics-apiserver:
    Image:           ghcr.io/kedacore/keda-metrics-apiserver:2.17.1
    Ports:           6443/TCP, 8080/TCP
    Host Ports:      0/TCP, 0/TCP
    SeccompProfile:  RuntimeDefault
    Command:
      /keda-adapter
...

That it is a metrics adapter deployed by KEDA:

$ kubectl get apiservices | grep metrics
v1beta1.external.metrics.k8s.io   keda/keda-operator-metrics-apiserver
v1beta1.metrics.k8s.io            kube-system/metrics-server

KEDA CRDs

The KEDA helm chart also deploys several Kubernetes Custom Resource Definitions (CRDs) that you will need to use in order to use KEDA.

$ kubectl api-resources | grep keda
cloudeventsources                                            eventing.keda.sh/v1alpha1         true         CloudEventSource
clustercloudeventsources                                     eventing.keda.sh/v1alpha1         false        ClusterCloudEventSource
clustertriggerauthentications       cta,clustertriggerauth   keda.sh/v1alpha1                  false        ClusterTriggerAuthentication
scaledjobs                          sj                       keda.sh/v1alpha1                  true         ScaledJob
scaledobjects                       so                       keda.sh/v1alpha1                  true         ScaledObject
triggerauthentications              ta,triggerauth           keda.sh/v1alpha1                  true         TriggerAuthentication

The main custom resources you will find yourself using are: ScaledObjects, ScaledJobs and TriggerAuthentication. The documentation of each built-in scaler will have an example that includes at least one of these.

Available Scalers

Now that KEDA is installed, you can explore KEDA’s set of built-in scalers1: to find the event source (scaler) you want KEDA to collect data and events from to determine whether or not a workload should be automatically scaled up or down.

Each built-in scaler has its own page with an example configuration and specifications that include how to configure KEDA to connect to the event source and what scaling options are available.

External Scalers

If the event source you want to use does not have a built-in scaler, KEDA provides support for external scalers. To use an external scaler, you will need to extend KEDA with a gRPC service. More information about setting up external scalers can be found in the official KEDA documentation2.

KEDA ScaledObjects

Scaling Pods with ScaledObjects

If your objective is to use KEDA to automatically scale the number of pod replicas (for a Deployment or StatefulSet), you will need to deploy a ScaledObject3 which uses the Kubernetes Horizontal Pod Autoscaler (HPA) under the hood.

Assuming the target deployment exists, if you deploy a properly configured KEDA ScaledObject

ScaledObject Example
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: scale-example
  namespace: default
spec:
  scaleTargetRef:
    apiVersion:    apps/v1
    kind:          Deployment
    name:          example
  pollingInterval: 3
  cooldownPeriod:  30
  minReplicaCount: 1
  maxReplicaCount: 5
  advanced:
    horizontalPodAutoscalerConfig:
      behavior:
        scaleDown:
          stabilizationWindowSeconds: 30
          policies:
          - type: Pods
            value: 1
            periodSeconds: 3
        scaleUp:
          stabilizationWindowSeconds: 0
          policies:
          - type: Pods
            value: 1
            periodSeconds: 3
  triggers:
  - type: prometheus
    metadata:
      serverAddress: PROMETHEUS_URL
      metricName: METRIC_NAME
      query: PROMETHEUS_QUERY
      threshold: '90'

…will cause KEDA will create a HorizontalPodAutoscaler object based on the specifications found in the ScaledObject:

Generated HorizontalPodAutoscaler Example
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  labels:
    app.kubernetes.io/managed-by: keda-operator
    app.kubernetes.io/name: keda-hpa-scale-example
    app.kubernetes.io/part-of: scale-example
    app.kubernetes.io/version: 2.17.1
    scaledobject.keda.sh/name: scale-example
  name: keda-hpa-scale-example
  namespace: default
  ownerReferences:
  - apiVersion: keda.sh/v1alpha1
    blockOwnerDeletion: true
    controller: true
    kind: ScaledObject
    name: scale-example
    uid: 6ab2ca5c-8dc6-4bd9-9245-14eb0cb79f60
spec:
  behavior:
    scaleDown:
      policies:
      - periodSeconds: 3
        type: Pods
        value: 1
      selectPolicy: Max
      stabilizationWindowSeconds: 30
    scaleUp:
      policies:
      - periodSeconds: 3
        type: Pods
        value: 1
      selectPolicy: Max
      stabilizationWindowSeconds: 0
  maxReplicas: 5
  metrics:
  - external:
      metric:
        name: s0-prometheus
        selector:
          matchLabels:
            scaledobject.keda.sh/name: scale-example
      target:
        averageValue: "90"
        type: AverageValue
    type: External
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: example
status:
  conditions:
  - lastTransitionTime: "2025-04-15T09:38:19Z"
    message: the HPA controller was able to get the target's current scale
    reason: SucceededGetScale
    status: "True"
    type: AbleToScale
  - lastTransitionTime: "2025-04-15T09:38:19Z"
    message: 'the HPA was unable to compute the replica count: unable to get external
      metric example/s0-prometheus/&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name:
      scale-example,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch
      metrics from external metrics API: rpc error: code = Unknown desc = error when
      getting metric values metric:s0-prometheus encountered error'
    reason: FailedGetExternalMetric
    status: "False"
    type: ScalingActive
  currentMetrics:
  - type: ""
  currentReplicas: 1
  desiredReplicas: 0

If you examine the HorizontalPodAutoscaler object generated by KEDA:

  • The metadata contains labels and a owner reference to link the HPA object with KEDA and the deployed ScaledObject object that was used to generate the HPA object.

  • KEDA translates the scaling configurations defined in the deployed ScaledObject to the appropriate HPA equivalent.

    • Not all configurations defined in the ScaledObject object are translated. The spec.pollingInterval defined in the ScaledObject object cannot be found in the generated HorizontalPodAutoscaler object. This is because spec.pollingInterval defines KEDA’s polling interval for the specific ScaledObject. HPA has its own polling interval set using the --horizontal-pod-autoscaler-sync-period flag for the kube-controller-manager.
  • The status of the generated HorizontalPodAutoscaler object shows an error message that starts with the HPA was unable to compute the replica count: unable to get external metric. This error message is also reported by KEDA, you can found it outputted in the logs of a KEDA operator pod, which, after stripping all the metadata and traces, reads:

    dial tcp: lookup PROMETHEUS_HOST: no such host
    

Scaling Custom Resources with ScaledObjects

If you want to scale a custom resource then you will also need to deploy a ScaledObject, but the Custom Resource Definition (CRD) must define the /scale subresource otherwise KEDA will not be able to scale the custom resource. You can confirm if the CRD defines the /scale subresource by running kubectl get crd CRD_NAME -o yaml and checking if .spec.versions[X].subresources.scale exists. If the fields is present, the CRD supports the /scale subresource and can be scaled by KEDA4.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
spec:
  versions:
    - name: v1
      subresources:
        scale:

Polling Intervals

Between HPA and KEDA, there are two different polling intervals:

  1. The Kubernetes HPA has a polling interval for all HPA objects. It is the value set with the --horizontal-pod-autoscaler-sync-period flag for the kube-controller-manager. In each sync period, the controller manager checks each HorizontalPodAutoscaler object and makes a scaling decision for each one5.
  2. When configuring ScaledObject or ScaledJob, you can set a pollingInterval for each one. This is the interval KEDA uses to check the event source.

KEDA Activation and Scaling Phases

The documentation for some KEDA scalers can give you two parameters that serve as thresholds triggering a scaling operations. One of parameters is to inform KEDA when to enter the “Activation Phase” and the other parameter is to inform KEDA when to enter the “Scaling Phase”6.


For a KEDA ScaledObject:

  • The “Activation Phase” is a threshold KEDA uses to determine whether or not to scale a workload to or from zero
  • The “Scaling Phase” is a threshold used to determine whether or not to scale a workload with at least one pod replica, but, in the scaling phase KEDA let’s the native Kubernetes HPA handle the scaling decision based on the HPA object created by KEDA.

For example, KEDA’s Redis List scaler has the listLength and activationListLength parameters. If both values are declared in a ScaledObject, KEDA will generate a HPA object with the value set to listLength somewhere in the HPA’s specification because the HPA controller will be using it to make it’s scaling decisions, but the value of activationListLength will not included in HPA object’s specification.

During each sync period, the Kubernetes HPA’s request for the metrics defined in a HPA object generated by KEDA will be routed to the KEDA Metrics Servers7.


⚠️ For a KEDA ScaledJob there is no HPA object created by KEDA.

Pausing Autoscaling

KEDA also supports pausing autoscaling by adding specifics annotations to a ScaledObject or ScaledJob. Useful if you want to perform a maintenance operation or when you want to temporarily prevent KEDA automatically scaling a particular workload.

KEDA ScaledJobs

Scaling Jobs with ScaledJobs

If your objective is to use KEDA to deploy Kubernetes Jobs in response to an event (e.g. to have the Jobs process the event(s)), you will need to create a ScaledJob8.

If you deploy the following custom Kubernetes resource ScaledJob

ScaledJob Example
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
  name: redis-job
spec:
  jobTargetRef:
    parallelism: 1
    completions: 1
    activeDeadlineSeconds: 30
    backoffLimit: 6
    template:
      spec:
        containers:
          - image: alpine:3.13.5
            name: alpine
            command: ['echo', 'hello world']
        restartPolicy: Never
  pollingInterval: 3
  successfulJobsHistoryLimit: 5
  failedJobsHistoryLimit: 5
  maxReplicaCount: 10
  scalingStrategy:
    strategy: "accurate"
  triggers:
  - type: redis
    metadata:
      address: redis.redis.svc.cluster.local:6379
      listName: mylist
      listLength: "1"
    authenticationRef:
      name: keda-trigger-auth-redis-secret

…KEDA will NOT create a HorizontalPodAutoscaler object.

If you examine the ScaledJob example object:

  • There is a spec.jobTargetRef key that defines the Kubernetes Job that will be created each time the scale up event is triggered.
  • There is a spec.triggers[0].authenticationRef.name key that references a deployed TriggerAuthentication KEDA custom object that contains the information KEDA will use to authenticate against the event/trigger source.
    • If you check the ScaledObject specification, you will see that this method of authentication can also be defined for ScaledObjects

Scaler Authentication

By design, KEDA will have to access services defined as trigger/event sources, but for security reasons, many services require users or other services to go through an authentication workflow before granting access. KEDA offers several different patterns for managing authentication workflows:

  1. Authentication per ScaledObject or ScaledJob: You can choose to provide KEDA the credentials for a scaler in the ScaledObject or ScaledJob. For example:

    triggers:
    - type: prometheus
    metadata:
      ...
      authModes: "bearer"
      bearerToken: "TOKEN"
    
  2. The preferred method is to set the authentication parameters in either a cluster-scoped ClusterTriggerAuthentication or a namespaced scoped TriggerAuthentication (both are KEDA custom resources) and reference them in an ScaledObject or ScaledJob object.

Within a TriggerAuthentication object there are many supported authentication workflows and methods supported by KEDA9, which include:

  • Setting up AWS, Azure or GCP pod identity providers
  • Fetching credentials from a source supported by KEDA (e.g. Kubernetes secrets, Hashicorp Vault, Azure Key Vault, AWS Secret Manager, etc)

KEDA Logs

As you start using KEDA, it’s important to familiarise yourself with the type of logs that can be outputted by KEDA, especially to understand how KEDA responds when something goes wrong.

For example, if the credentials you provided to KEDA expire or become misconfigured KEDA will output a log similar to the one below…

"connection to redis failed: NOAUTH Authentication required."

…or KEDA might fail to get a scaling decision…

"prometheus query increase(
  http_requests_total{namespace=\"example\", container=\"example\", status=\"200\"}[5m])
returned multiple elements"

…or maybe the target workloads can no longer be found leaving you with KEDA (and HPA) objects in your Kubernetes cluster but providing no value.

"Deployment.apps \"example\" not found"

Also, when KEDA is functioning as expected, you may find the KEDA workloads output a lot of logs which may become a problem when storing your log data.

You should make sure to invest time in understanding how KEDA behaves in both normal and error scenarios, this understanding will help you effectively setup monitoring and alerting systems around the scaling infrastructure enabled by KEDA. For example, while you are using KEDA on a small scale, it’s a good idea to start analysing these logs and plan out how you will aggregate them.

KEDA Metrics

You also want to consider pushing KEDA related metrics into your observability system. The KEDA Operator exposes Prometheus metrics and also has an experimental feature to push metrics to a OpenTelemetry Collector. To get started visualising these metrics, there is a pre-made Grafana dashboard.

Modifying Scaling Behaviour

Once you have deployed a ScaledObject or ScaledJob you should run tests to confirm KEDA is able to access/monitor the event source and automatically scale your target workloads after the threshold you set have been exceeded. As you run these tests, observe how quickly your workloads have scaled up and down, then fine-tune the scaling behaviour defined in the ScaledObject or ScaledJob.

  • The ScaledObject specification has scaling modifiers (advanced.scalingModifiers) that can be used to create a dynamic scaling strategy, for example, you can select select one or more metrics, insert them into a mathematical formula and set an activation threshold for scale operations to the current value returned by the formula.
    • You can also define the scaling behaviour in the HPA object created by KEDA (advanced.horizontalPodAutoscalerConfig.behavior).
  • The ScaledJob specification provides you the option to define a scaling strategy (scalingStrategy)

You should experiment with the different scaling strategy, collect data as you test each one and determine the best scaling strategy for your workloads.

Keda Concepts Summary

All of the above is an overview of some of the KEDA concepts I believe will be beneficial when experimenting with KEDA for the first time and figuring out how KEDA can be used to setup the most optimal autoscaling strategy for Kubernetes workloads.

The subsequent parts of this blog series will include demos of using the various features of KEDA with it’s various supported scalers.

Footnotes

This blog is part of our KEDA series, we recommend reading the rest of the posts in the series:

  1. Introducing Kubernetes Event-driven Autoscaling (KEDA)
  2. Getting Started with Autoscaling in Kubernetes with KEDA
  3. Autoscaling workloads with KEDA and the Prometheus Scaler