Kedify Pod Autoscaler
Kedify Pod Autoscaler (KPA) is a tenant-scoped horizontal autoscaler for the Kedify build of KEDA. KEDA continues to activate workloads and handle the 0 ↔ 1 boundary. KPA controls scaling between 1 ↔ N replicas.
Why use KPA
Section titled “Why use KPA”Native KEDA creates Kubernetes HorizontalPodAutoscalers (HPAs), which share the cluster’s HPA controller and external-metrics API path. KPA lets each tenant operate its own autoscaling control loop beside its KEDA operator. This is useful when a large cluster needs stronger autoscaling isolation, separate tenant ownership, or independent control-plane capacity.
KPA reads external metrics from its paired KEDA operator. CPU and memory metrics continue to use Kubernetes metrics.k8s.io.
ScaledObject compatibility
Section titled “ScaledObject compatibility”The ScaledObject remains the source of truth. Existing settings stay in the same fields, including:
minReplicaCountandmaxReplicaCount;- trigger metric targets and fallback configuration; and
advanced.horizontalPodAutoscalerConfig, including scaling policies and stabilization windows.
KPA uses the Kubernetes autoscaling/v2 HPA spec and status shape. Do not create KPA resources manually; user-authored KPAs are not supported.
Install or upgrade KPA
Section titled “Install or upgrade KPA”The following example installs one default multitenant KEDA/KPA pair that watches tenant-a. Replace the version placeholders with released chart versions and adjust release names, namespaces, and watchNamespace for your environment.
First install or upgrade KEDA with KPA disabled. This keeps existing workloads on HPA while KEDA creates its MetricsService and TLS Secret:
helm upgrade --install keda kedifykeda/keda \ --version <KEDA_VERSION> \ --namespace keda --create-namespace \ --set kedify.multitenant.mode=default \ --set-string watchNamespace=tenant-a \ --set kedify.kpa.enabled=false \ --set kedify.kpa.defaultClass=hpaInstall the matching KPA release with the same namespace watch set. Exactly one designated KPA release should install the cluster-scoped CRD:
helm upgrade --install kpa oci://ghcr.io/kedify/charts/kpa \ --version <KPA_VERSION> \ --namespace keda \ --set crds.install=true \ --set-string watchNamespace=tenant-aWait for both controllers, then enable KPA in KEDA while keeping HPA as the default for the initial canary:
kubectl rollout status deployment/keda-operator -n kedakubectl rollout status deployment/kpa-controller -n keda
helm upgrade keda kedifykeda/keda \ --version <KEDA_VERSION> \ --namespace keda \ --reuse-values \ --set kedify.kpa.enabled=true \ --set kedify.kpa.defaultClass=hpaIf the Kedify Agent is installed, enable its KPA integration for Dashboard access and telemetry:
helm upgrade kedify-agent kedifykeda/kedify-agent \ --version <AGENT_VERSION> \ --namespace keda \ --reuse-values \ --set agent.features.kedifyPodAutoscalerEnabled=trueFor a new Agent installation, add agent.features.kedifyPodAutoscalerEnabled=true to the installation command supplied by the Kedify Dashboard.
Canary one low-risk ScaledObject before changing kedify.kpa.defaultClass to kpa. Confirm that the workload has one KPA, no HPA targets the same workload, and scaling and events are healthy.
For multiple tenants, repeat the KEDA/KPA installation with distinct release namespaces and non-overlapping watchNamespace values. Set crds.install=false on every additional KPA release. The designated default KEDA release owns the cluster-wide admission webhook; keep KPA enabled there and keep its defaultClass aligned with tenant releases whenever ScaledObjects use the installation default. See Multitenant KEDA for the tenant installation model.
Select KPA for a ScaledObject
Section titled “Select KPA for a ScaledObject”Select KPA without changing the ScaledObject spec:
metadata: annotations: autoscaling.kedify.io/class: kpaThe annotation overrides the installation default. Remove it to follow kedify.kpa.defaultClass, or set it to hpa to select native HPA explicitly. KEDA manages the transition and prevents HPA and KPA from controlling the workload at the same time.
ScalingGroup fallback
Section titled “ScalingGroup fallback”ScalingGroup members use native HPA. If an explicitly KPA-selected ScaledObject joins a group, Kedify changes its class to hpa and emits an AutoscalingClassFallback event. That HPA selection remains after it leaves the group; select kpa again to opt back in. A ScaledObject that used KPA only through the installation default returns to that default after leaving the group.
Configure the KPA evaluation interval
Section titled “Configure the KPA evaluation interval”Override the controller-wide interval for one ScaledObject:
metadata: annotations: autoscaling.kedify.io/class: kpa autoscaling.kedify.io/sync-period-seconds: "15"The value is an integer from 1 through 3600 seconds and cannot be lower than the KPA installation’s minimum interval, which defaults to five seconds. Without the annotation, KPA uses its controller-wide sync period, which defaults to 15 seconds.
This setting controls how often KPA evaluates the autoscaler. It is separate from ScaledObject pollingInterval, which controls KEDA trigger polling and affects activation from zero.
Use KPA in the Dashboard
Section titled “Use KPA in the Dashboard”The Dashboard exposes Pod autoscaler class and KPA evaluation interval under Advanced configuration. The ScaledObject list can display and filter the selected class, and View pod autoscaler opens the generated HPA or KPA.
The Dashboard verifies that KPA is available in the selected namespace before accepting a new KPA selection. KEDA admission performs the final validation. Existing KPA selections are preserved during a temporary availability or permission failure.
Supported metrics
Section titled “Supported metrics”| Metric source | KPA backend |
|---|---|
External | Paired KEDA operator |
Resource | Kubernetes metrics.k8s.io |
ContainerResource | Kubernetes metrics.k8s.io |
Object and Pods metric sources are not supported. KPA does not independently scale to zero; KEDA continues to own activation, cooldown, and the 0 ↔ 1 transition.
Observe and troubleshoot KPA
Section titled “Observe and troubleshoot KPA”The KPA controller exposes /healthz, /readyz, and /metrics. The Helm chart enables scrape annotations by default. Set both serviceMonitor.enabled=true and prometheusRule.enabled=true to install the supplied ServiceMonitor and alerts.
Start troubleshooting with the ScaledObject, generated autoscaler, target, and events:
kubectl get scaledobject,hpa,kpa -n tenant-akubectl get scaledobject orders -n tenant-a -o jsonpath='{.status.hpaName}{"\n"}'kubectl describe kpa keda-hpa-orders -n tenant-akubectl get events -n tenant-a --sort-by=.lastTimestampIf external metrics fail, check the paired KEDA operator, its MetricsService and TLS Secret, and the namespace watch configuration. For CPU or memory failures, verify metrics.k8s.io with kubectl top pods -n tenant-a.
Roll back to HPA
Section titled “Roll back to HPA”Keep KPA enabled while moving workloads back:
- Set
kedify.kpa.defaultClass=hpaon the designated webhook release and every tenant release. - Set
autoscaling.kedify.io/class: hpaon every ScaledObject that explicitly selects KPA. - Wait for KEDA to remove all KPAs, create replacement HPAs, and confirm those HPAs are healthy.
- Set
kedify.kpa.enabled=false, then remove the tenant KPA controller releases. - Remove the cluster-scoped KPA CRD last, only after no KPA objects or tenant installations remain. Helm retains the CRD on uninstall by default.
Current limitations
Section titled “Current limitations”- KPA is generated only from ScaledObjects; manually managed KPAs are unsupported.
- ScalingGroup members use native HPA.
- Tenant namespace ownership cannot overlap between KPA installations.
- Moving a live namespace between tenant controllers requires a controlled rollout.
- KPA supports Kubernetes 1.33 through 1.35.