Opening up KEDA's architecture: the operator that manages ScaledObject and ScaledJob, the metrics server that feeds metrics to HPA, admission webhooks, plus the main CRD components and the role of 70+ scalers.

In episode 1 we understood why KEDA exists: to scale workloads based on events, not CPU, and to scale replicas down to zero when there's no work. The natural next question is: how does it do it?
Episode 2 opens the hood. We'll look at the three components running in the keda namespace after installation, understand each one's role, and then get acquainted with the Custom Resource (CRD) objects you'll be writing over and over for the rest of this series.
When you install KEDA via Helm, three Deployments appear: keda-operator, keda-metrics-server, and keda-admission-webhooks. Each has a very different role.
The operator is KEDA's brain. It runs the reconciliation loop typical of the Kubernetes operator pattern: continuously comparing the real state with what's declared in the CRDs. When you create a ScaledObject or ScaledJob, the operator is responsible for two important things:
maxReplicaCount changes.apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-worker-scaledobject
spec:
scaleTargetRef:
name: order-worker
minReplicaCount: 0
maxReplicaCount: 10
triggers:
- type: rabbitmq
metadata:
queueName: ordersNote: you never create an HPA manually for this workload. The HPA is created and managed by the operator, and the following commands will show it:
kubectl get hpa
kubectl get scaledobject
kubectl describe scaledobject order-worker-scaledobjectThe second component is keda-metrics-server. It implements the Kubernetes External Metrics API. When the HPA (created by the operator) needs a number, it asks keda-metrics-server, which contacts the appropriate scaler to fetch the actual value — for example, RabbitMQ queue length — and returns it in a form HPA understands.
This is why KEDA "melts into" the Kubernetes ecosystem without extra plugins: HPA doesn't know or care that its data comes from Kafka or SQS. All it sees is an external metric with a specific name.
The third component is keda-admission-webhooks. As the name suggests, it provides webhook endpoints that Kubernetes calls every time a KEDA object is created or modified. Its job is validation: is maxReplicaCount greater than minReplicaCount? Is the scaler name being used actually registered? If not, the object is rejected before it can damage the cluster state.
Warning
The webhook is why kubectl apply -f my-scaledobject.yaml sometimes fails with a strange message even though the YAML is valid. Read the webhook error message carefully — it usually already explains which field is wrong.
To understand how neat KEDA's design is, follow one metric request cycle from start to finish:
ScaledObject and creates an HPA targeting your deployment.pollingInterval, the HPA requests the external metric value from keda-metrics-server.threshold.RabbitMQ --> keda-metrics-server --> External Metrics API --> HPA --> DeploymentThe key to this entire flow: HPA remains the only final decision maker. KEDA merely provides more relevant data. That's why replica scaling behavior can still be tuned through HPA mechanisms like behavior for scaleUp and scaleDown — which we'll cover in episode 11.
All KEDA configuration happens through four Custom Resources. Mastering all four means mastering 80 percent of KEDA.
ScaledObject (with scaledobjects.keda.sh) manages autoscaling for continuous workloads like Deployment, StatefulSet, or ReplicaSet. Its main fields are scaleTargetRef (points at the workload), pollingInterval, cooldownPeriod, minReplicaCount, maxReplicaCount, and triggers. Episode 4 covers it in full.
ScaledJob manages Job autoscaling (Kubernetes Jobs for batch workloads). The fundamental difference from ScaledObject: instead of adding/removing replicas of an already-running pod, KEDA creates a new Job whenever there's an event — behavior better suited to tasks that have a beginning and an end.
Most scalers need credentials to access the event source — for example, SQS secrets or Kafka certificates. Those credentials are defined in TriggerAuthentication (scoped to one namespace) or ClusterTriggerAuthentication (scoped across namespaces), then referenced from triggers in the ScaledObject. We'll dig into the details in episode 6.
The part that makes KEDA so compelling: the collection of ready-made scalers. Each scaler is an implementation for one specific metric source:
spec:
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring:9090
query: sum(rate(worker_processed_total[2m]))
threshold: "10"
- type: cron
metadata:
timezone: Asia/Jakarta
start: "0 8 * * *"
end: "0 18 * * *"As of 2026, the collection already has more than 70 scalers, and they can be grouped by category:
| Category | Example Scaler |
|---|---|
| Queue & Stream | SQS, Kafka, RabbitMQ, Redis Streams, NATS JetStream |
| Cloud queue | Azure Service Bus, GCP Pub/Sub |
| Observability | Prometheus, Grafana |
| HTTP | HTTP Add-on (pending requests) |
| Database | PostgreSQL, MySQL, MongoDB, Redis list |
| Schedule | cron (predictive) |
| Resource | CPU, memory |
| Others | GitHub, external-push |
The full official list can always be checked in the keda.sh documentation. Those three architecture components plus these four CRDs are the package you'll use in every following episode.
Episode 2 gives you the map of KEDA's architecture. Here's what you must bring along:
In episode 3 we'll get hands-on: installing KEDA from scratch with Helm, configuration options via --set, and a manifest-based installation alternative for GitOps flows.