Getting Started with Autoscaling in Kubernetes with KEDA
Considering using KEDA for autoscaling? Understanding these KEDA features and concepts may help you
Published on:
Jun 2, 2025Last updated on:
Jun 9, 2025This blog is part of our KEDA series, we recommend reading the rest of the posts in the series:
- Introducing Kubernetes Event-driven Autoscaling (KEDA)
- Getting Started with Autoscaling in Kubernetes with KEDA
- 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 ScaledObject
3 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. Thespec.pollingInterval
defined in theScaledObject
object cannot be found in the generatedHorizontalPodAutoscaler
object. This is becausespec.pollingInterval
defines KEDA’s polling interval for the specificScaledObject
. HPA has its own polling interval set using the--horizontal-pod-autoscaler-sync-period
flag for thekube-controller-manager
.
- Not all configurations defined in the
The status of the generated
HorizontalPodAutoscaler
object shows an error message that starts withthe 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:
- 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 thekube-controller-manager
. In each sync period, the controller manager checks eachHorizontalPodAutoscaler
object and makes a scaling decision for each one5. - When configuring
ScaledObject
orScaledJob
, you can set apollingInterval
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 ScaledJob
8.
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 deployedTriggerAuthentication
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 forScaledObject
s
- If you check the
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:
Authentication per
ScaledObject
orScaledJob
: You can choose to provide KEDA the credentials for a scaler in theScaledObject
orScaledJob
. For example:triggers: - type: prometheus metadata: ... authModes: "bearer" bearerToken: "TOKEN"
The preferred method is to set the authentication parameters in either a cluster-scoped
ClusterTriggerAuthentication
or a namespaced scopedTriggerAuthentication
(both are KEDA custom resources) and reference them in anScaledObject
orScaledJob
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
).
- You can also define the scaling behaviour in the HPA object created by KEDA (
- 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:
- Introducing Kubernetes Event-driven Autoscaling (KEDA)
- Getting Started with Autoscaling in Kubernetes with KEDA
- Autoscaling workloads with KEDA and the Prometheus Scaler