KEDA simplifies scaling in Kubernetes, supporting custom metrics and external events for efficient resource management.

CTO
João Brito

KEDA is a scaling platform for Kubernetes that is changing how companies manage their resources within Kubernetes.
KEDA makes scaling simple and automated, allowing users to scale their applications and services efficiently and with minimal effort.
KEDA's major differentiator is its flexibility and adaptability. The platform can horizontally scale any workload, regardless of the type of application or service running. In addition, KEDA is compatible with a variety of cloud providers and monitoring tools, allowing users to customize the platform to meet the specific needs of their businesses.
If you don't want to scale your applications based solely on CPU and memory, but rather by observing other metrics or external events, this is the tool that will help you with horizontal scalability. Spinning up or down pods as your stack demands.
KEDA, Kubernetes Event-Driven Autoscaling, is an automatic pod autoscaler based on external events. We can easily scale our pods based on local CPU and memory metrics, but what about when we have an external event that precedes their usage? For example, a messaging queue, a database table, an ElasticSearch query, Kafka, Redis, Prometheus external to your cluster, and so on.
There are several technical advantages to using KEDA instead of the Horizontal Pod Autoscaler (HPA) to scale applications in Kubernetes. Here are some of them:
Support for custom metrics: KEDA supports custom metrics, allowing users to scale their applications and services based on specific metrics other than CPU and memory. This allows users to customize the platform to meet the specific needs of their applications.
Support for multiple event sources: KEDA is compatible with multiple event sources, including Kafka, RabbitMQ, and Azure Service Bus. This allows users to scale their applications based on events rather than just metrics.
Resource authentication: KEDA supports resource authentication, allowing users to securely authenticate access to scaling resources. This helps protect Kubernetes cluster resources from unauthorized access.
Fast scalability: KEDA offers fast and precise scalability. The platform uses advanced real-time scalability technologies to ensure resources are used efficiently and effectively. This allows users to scale quickly based on custom metrics and other conditions.
Greater resource efficiency: KEDA is highly resource-efficient, allowing users to scale their applications with the minimum resources required. This helps save money and improve the performance of the Kubernetes cluster.
Better integration with cloud providers: KEDA offers better integration with cloud providers, including Azure, AWS, and Google Cloud. This allows users to customize the platform to meet their specific business needs and leverage the cloud provider's resources.
Scale pods to ZERO units: Unlike HPA, KEDA allows turning down deploy pod units to zero and using a trigger to scale according to demand.
Let's start with KEDA's architecture:

Let's see how it actually works, for this we will install KEDA in a Kubernetes cluster and create a queue in SQS to use as a trigger
We will use a Kind cluster to test.
cat <<EOF | kind create cluster --config -
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: demo
nodes:
- role: control-plane
image: kindest/node:v1.24.7@sha256:577c630ce8e509131eab1aea12c022190978dd2f745aac5eb1fe65c0807eb315
- role: worker
image: kindest/node:v1.24.7@sha256:577c630ce8e509131eab1aea12c022190978dd2f745aac5eb1fe65c0807eb315
EOF
Creating cluster "demo" ...
✓ Ensuring node image (kindest/node:v1.24.7) 🖼
✓ Preparing nodes 📦 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
✓ Joining worker nodes 🚜
Set kubectl context to "kind-demo"
You can now use your cluster with:
kubectl cluster-info --context kind-demo
Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
Installing KEDA:
# Add KEDA's helm repository
helm repo add keda https://kedacore.github.io/charts
# Update your repositories
helm repo update
# Install KEDA chart
helm install keda keda/keda -n keda --create-namespace
Creating a simple application to test
kubectl create deploy web --image nginx
Create an AWS SQS queue (standard queue)
In AWS Console -> AWS SQS -> Standard Queue, copy the region and the queue URL.

Creating a KEDA object, ScaledObject and its authentication in AWS
cat <<EOF | kubectl apply -f -
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: aws-sqs-queue-scaledobject
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1 # Optional. Default: apps/v1
kind: Deployment # Optional. Default: Deployment
name: web # Mandatory. Must be in the same namespace as this ScaledObject
pollingInterval: 5 # Polling interval
cooldownPeriod: 10 # Optional. Default 300s
idleReplicaCount: 0 # Optional. When idle, scales to 0 pod.
minReplicaCount: 0 # Optional. Default 0
maxReplicaCount: 3 # Optional. Default 100
fallback: # Optional. Fallback strategy when metrics are not available
failureThreshold: 5 # if metrics unavailable, keeps the replica count below
replicas: 2 # item above
triggers:
- type: aws-sqs-queue
authenticationRef:
name: keda-trigger-auth-aws-credentials # Authentication pointing to AWS access
metadata:
queueURL: https://sqs.us-east-2.amazonaws.com/12345678909/my-sqs-keda
queueLength: "5"
awsRegion: "us-east-2"
EOF
cat <<EOF | kubectl apply -f -
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
name: keda-trigger-auth-aws-credentials
namespace: default
spec:
secretTargetRef:
- parameter: awsAccessKeyID # Required.
name: test-secrets # Required.
key: AWS_ACCESS_KEY_ID # Required.
- parameter: awsSecretAccessKey # Required.
name: test-secrets # Required.
key: AWS_SECRET_ACCESS_KEY # Required.
EOF
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: test-secrets
Namespace: default
data:
AWS_ACCESS_KEY_ID: <encoded-user-id> # Required.
AWS_SECRET_ACCESS_KEY: <encoded-key> # Required.
EOF
KEDA supports for the type ScaledObjects: Deployments, StatefulSets or CustomResources such as an ArgoRollout for example.
Let's explain the ScaledObject above:
1- The ScaledObject will be created in the default namespace.
2- It will manage the replicas of the 'web' Deployment.
3 - The event source will be an AWS SQS with the queue https://sqs.us-east-2.amazonaws.com/12345678909/my-sqs-keda in the us-east-2 region.
4- The queue length that triggers the scaling is 5, meaning when it reaches 5, it increases by 1 pod, this happens for every 5 backed up messages.
5- The idleReplicaCount is 0, which reduces to 0 pods if the queue is empty.
6- Fallback enabled means if there is a failure in obtaining the queue length, 2 running replicas will be maintained.
7- The triggerAuthentication is how this ScaledObject will gain access to the SQS queue, which in turn references a secret with AWS credentials. Thinking about security this is not the best way, there is a way to use IAM Role and assign to nodes or serviceAccount in the cluster, as documented here.
Finally, the creation of the ScaledObject creates a 'child' HPA object that controls the amount of pods based on the triggers section.
Action Time!
1 - Observe your web deployment
kubectl get deployments web -n default --watch
NAME READY UP-TO-DATE AVAILABLE AGE
web 0/0 0 0 4h52m
2 - Add some messages to the queue, more than 5 to see the pods scale;

Result: KEDA will scale your pods
kubectl get deployments web -n default --watchNAME READY UP-TO-DATE AVAILABLE AGE
Web 0/0 0 0 4h52m
web 0/1 0 0 4h54m
web 0/1 0 0 4h54m
web 0/1 0 0 4h54m
web 0/1 1 0 4h54m
web 1/1 1 1 4h54m
web 1/2 1 1 4h54m
web 1/2 1 1 4h54m
web 1/2 1 1 4h54m
Web 1/2 2 1 4h54m
Web 2/2 2 2 4h54m
Once the queue becomes idle, your deploy will automatically be scaled to 0.
Conclusion
We saw how KEDA creates the HPA and acts directly on it by scaling the pods, this can be observed in the namespace events and in the hpa description:
kubectl get events -n default
LAST SEEN TYPE REASON OBJECT MESSAGE
23s Normal SuccessfulRescale horizontalpodautoscaler/keda-hpa-aws-sqs-queue-scaledobject New size: 2; reason: external metric s0-aws-sqs-my-sqs-keda(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: aws-sqs-queue-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
68s Normal Killing pod/web-68bdbdcb94-48c54 Stopping container nginx
23s Normal Scheduled pod/web-68bdbdcb94-d9hql Successfully assigned default/web-68bdbdcb94-d9hql to demo-worker3
23s Normal Pulling pod/web-68bdbdcb94-d9hql Pulling image "nginx"
22s Normal Pulled pod/web-68bdbdcb94-d9hql Successfully pulled image "nginx" in 1.196212139s
22s Normal Created pod/web-68bdbdcb94-d9hql Created container nginx
21s Normal Started pod/web-68bdbdcb94-d9hql Started container nginx
39s Normal Scheduled pod/web-68bdbdcb94-lnsjj Successfully assigned default/web-68bdbdcb94-lnsjj to demo-worker4
38s Normal Pulling pod/web-68bdbdcb94-lnsjj Pulling image "nginx"
33s Normal Pulled pod/web-68bdbdcb94-lnsjj Successfully pulled image "nginx" in 5.913160223s
33s Normal Created pod/web-68bdbdcb94-lnsjj Created container nginx
32s Normal Started pod/web-68bdbdcb94-lnsjj Started container nginx
68s Normal SuccessfulDelete replicaset/web-68bdbdcb94 Deleted pod: web-68bdbdcb94-48c54
39s Normal SuccessfulCreate replicaset/web-68bdbdcb94 Created pod: web-68bdbdcb94-lnsjj
23s Normal SuccessfulCreate replicaset/web-68bdbdcb94 Created pod: web-68bdbdcb94-d9hql
39s Normal ScalingReplicaSet deployment/web Scaled up replica set web-68bdbdcb94 to 1
68s Normal ScalingReplicaSet deployment/web Scaled down replica set web-68bdbdcb94 to 0
23s Normal ScalingReplicaSet deployment/web Scaled up replica set web-68bdbdcb94 to 2
kubectl describe hpa
Name: keda-hpa-aws-sqs-queue-scaledobject
Namespace: default
Labels: app.kubernetes.io/managed-by=keda-operator
app.kubernetes.io/name=keda-hpa-aws-sqs-queue-scaledobject
app.kubernetes.io/part-of=aws-sqs-queue-scaledobject
app.kubernetes.io/version=2.9.1
scaledobject.keda.sh/name=aws-sqs-queue-scaledobject
Annotations: <none>
CreationTimestamp: Tue, 03 Jan 2023 10:17:30 -0300
Reference: Deployment/web
Metrics: ( current / target )
"s0-aws-sqs-my-sqs-keda" (target average value): 3 / 5
Min replicas: 1
Max replicas: 3
Deployment pods: 2 current / 2 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale recommended size matches current size
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from external metric s0-aws-sqs-my-sqs-keda(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: aws-sqs-queue-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},})
ScalingLimited False DesiredWithinRange the desired count is within the acceptable range
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 34s horizontal-pod-autoscaler New size: 2; reason: external metric s0-aws-sqs-my-sqs-keda(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: aws-sqs-queue-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
We used an SQS queue on AWS as an external object, but it could be any system or application that generates some metric that can be collected, including via Prometheus installed in your cluster receiving metrics of this same type from applications internal and external to the cluster. I also did a very practical Lab here on the blog last year: https://gtup.me/kubilab-keda01
References
Newsletter Getup.
Atualizações sobre Kubernetes e Software Supply Chain Security todos os meses.
Operating Kubernetes in production for more than 13 years. With Quor, this experience extends to software supply chain security as well.
GET UP
© Getup · 2026

