As discussed in our previous articles, there are different solutions for scaling your Red Hat OpenShift compute infrastructure. In our first article, we demonstrated the built-in, Kubernetes-native Cluster Autoscaler, and in our second article we demonstrated the metrics-driven MachineSet Autoscaler with KEDA.
Cluster Autoscaler is integrated with the Red Hat OpenShift Machine API and relies on 2 custom resources: The cluster-wide ClusterAutoscaler and the per-MachineSet MachineAutoscaler.
Conversely, the MachineSet Autoscaler with KEDA utilizes the Custom Metrics Autoscaler operator to scale infrastructure based on external or custom signals (such as PromQL queries).
The most significant distinction between these methods is the trigger mechanism used to initiate a scale-up event. Cluster Autoscaler is primarily reactive. It monitors the cluster for Pending pods that cannot be scheduled due to insufficient CPU, memory, or node-specific constraints. KEDA, however, monitors specific metrics (such as global CPU utilization across a MachineSet) and scales at the defined threshold. This allows KEDA to add capacity before pods ever reach a Pending state.
This is a summary of the technical differences between the 2 autoscalers we looked at:
| Aspect | Cluster Autoscaler | KEDA MachineSet autoscaler |
|---|---|---|
| Trigger | Pending pods by default; also ProvisioningRequest / CapacityBuffer | Any metric (Prometheus, CloudWatch, Azure Monitor, etc.) |
| Scaling signal | Kubernetes scheduler simulation (plus ProvReq / buffer demand) | PromQL query / external metric |
| Proactive? | Default path is reactive; ProvReq (Dev Preview on OCP standalone) and CapacityBuffer enable predictive capacity | Yes, it scales on metric threshold before pods are Pending |
| Scale-up speed | Reactive + VM boot time (7–15 min total on Azure) | Metric-driven + VM boot time (same provisioning, earlier trigger) |
| Scale-down | Built-in (utilization < threshold, pod safety checks) | Via KEDA cooldownPeriod + metric falling below activation threshold |
| Configuration | ClusterAutoscaler + MachineAutoscaler CRDs | ScaledObject + RBAC + Prometheus auth |
| Operator | Machine API Operator (built-in) | Custom Metrics Autoscaler Operator (KEDA requires additional installation) |
| Scope | Cluster-wide limits; per-MachineSet bounds | Per-ScaledObject (one MachineSet per ScaledObject) |
| Formula control | None: autoscaler decides how many nodes to add | Full: PromQL query defines exact scaling behavior |
| Expanders | Random, LeastWaste, Priority | N/A (single target per ScaledObject) |
| Pod safety | Respects PDBs, local storage, safe-to-evict | No built-in pod safety for scale-down (relies on cooldownPeriod) |
| Scale-from-zero | Supported (capacity annotations required) | Supported (activation threshold or cold-start PromQL branch) |
| Conflicts | Must not coexist with KEDA on same MachineSet | Must not coexist with MachineAutoscaler on same MachineSet |
| HPA limitation | N/A | metricType: Value fails for MachineSets (no pods); requires AverageValue with compensating formula |
Configuration and safety features provide another point of divergence. Cluster Autoscaler is a native feature requiring no additional operators and includes sophisticated scale-down logic and pod-eviction safety. It is designed to handle general-purpose workloads across multiple MachineSets with global limits. MachineSet Autoscaler with KEDA requires the installation of the Custom Metrics Autoscaler operator and the configuration of custom RBAC and Prometheus authentication. It relies on a `cooldownPeriod`
and activation threshold to manage node removal.
Which autoscaler to choose
The choice between these methods depends on the predictability and type of workload demand.
When to use Cluster Autoscaler
- General-purpose workloads: Pods request resources, the scheduler places them, and infrastructure automatically scales to meet demand.
- Pod-shaped capacity signals: Scaling triggers from unschedulable pods or requests like ProvisioningRequest and CapacityBuffer, rather than external metrics.
- Predictive capacity within Cluster Autoscaler: You can use ProvisioningRequest for gang provisioning or CapacityBuffer for spare capacity, all within the standard Cluster Autoscaler model.
- Multiple MachineSets: One ClusterAutoscaler manages several MachineSets with set group and global limits. This eliminates the need for custom metrics on each MachineSet.
- Built-in scale-down safety: Features like PDB awareness and annotation controls handle eviction automatically without custom logic.
- No extra operators: Features work out of the box on any IPI OpenShift cluster.
When to use KEDA MachineSet autoscaler
- Metric-driven proactive scaling: Add nodes based on CPU usage, queue depth, or other signals before pods fail to schedule. For example, scale up when usage hits 75% instead of waiting for 100%. Use this approach when ProvisioningRequest or CapacityBuffer do not fit your metrics.
- Custom metrics: Base scaling decisions on queue depth, request rates, GPU usage, or external Prometheus metrics instead of pod templates or scheduler pressure.
- Predictable step-by-step growth: Use PromQL queries to define exact replica counts for each scaling threshold.
- Dedicated node pools: Manage tainted MachineSets for specialized workloads where scheduler pressure alone is not enough.
- Decoupled scaling logic: Allow application teams to set their own scaling rules through ScaledObjects without needing a cluster admin to configure the autoscaler.
Can the autoscalers coexist?
Yes, but NOT on the same MachineSet. This is an example valid topology:
| MachineSet | Autoscaler | Use case |
|---|---|---|
worker-eastus1 | Cluster Autoscaler (MachineAutoscaler ) | General workloads |
worker-eastus2 | Cluster Autoscaler (MachineAutoscaler ) | General workloads |
worker-eastus3 | KEDA (ScaledObject ) | Dedicated pool, metrics-driven |
If both target the same MachineSet, they will fight over the replica count and cause flapping.
Observed behavior on demo-p4p95
During our tests, we made some observations about each autoscaler.
The VM provisioning time is identical, but the difference is when the scale-up decision happens. KEDA triggers earlier because the metric exceeds the threshold as soon as pods are scheduled on the existing node, while Cluster Autoscaler waits for pods to be confirmed as unschedulable.
| Metric | Cluster Autoscaler (Part 1) | KEDA (Part 2) |
|---|---|---|
| Trigger latency | ~10 min (waited for CA scan loop) | ~1 min (30s polling + metric above threshold) |
| Scale-up decision | 1 → 3 in one shot (estimated all needed nodes at once) | 1 → 2 → 3 step-by-step (one replica per threshold breach) |
| Total time to 3 nodes | ~24 min (reaction + 2 VM boots) | ~15 min (faster trigger + 2 VM boots) |
| VM provisioning | ~7 min per node | ~7 min per node (same cloud, same VM size) |
| Signal | 6 Pending pods | CPU utilization 99% × nodeCount > threshold 75 |
Summary
The differences between Cluster Autoscaler and MachineSet Autoscaler with KEDA, In a concise, executive summary:
| Cluster Autoscaler | KEDA | |
|---|---|---|
| Philosophy | Match capacity to pod-shaped demand (Pending by default; ProvReq / CapacityBuffer for predictive cases) | Act on metric thresholds |
| Strength | Zero config for standard workloads; native predictive APIs for capacity-aware flows | Full control over when and how to scale from any metric |
| Weakness | Default path is reactive (pods wait during provisioning); ProvReq is Dev Preview on OCP standalone | Requires metric engineering and operator install |
| Best fit | General compute pools; gang / spare-capacity workflows inside CA | Dedicated pools with predictable, non-pod metric patterns |
Cluster Autoscaler provides a seamless solution with built-in scale-down safety for general-purpose OpenShift workloads driven by scheduler demand. KEDA MachineSet autoscaling offers highly fine-grained, metric-driven control for dedicated node pools, enabling proactive scaling before pods become unschedulable. Choosing the right tool depends on what your infrastructure strategy prioritizes.
Facts Only
* Red Hat OpenShift utilizes Cluster Autoscaler and KEDA MachineSet Autoscaler for compute scaling.
* Cluster Autoscaler relies on ClusterAutoscaler and MachineAutoscaler custom resources.
* KEDA uses the Custom Metrics Autoscaler operator and ScaledObject resources.
* Cluster Autoscaler triggers scale-up based on Pending pods, ProvisioningRequest, or CapacityBuffer.
* KEDA triggers scale-up based on metrics from Prometheus, CloudWatch, or Azure Monitor.
* VM provisioning time is approximately 7 minutes per node on Azure.
* Cluster Autoscaler is integrated into the Machine API Operator.
* KEDA requires additional installation of the Custom Metrics Autoscaler operator.
* Cluster Autoscaler respects Pod Disruption Budgets (PDBs) and local storage during scale-down.
* KEDA manages node removal via a cooldownPeriod and activation thresholds.
* Both autoscalers support scaling from zero.
* Simultaneous use of both autoscalers on a single MachineSet causes replica count flapping.
Executive Summary
Red Hat OpenShift compute infrastructure can be scaled using either the Kubernetes-native Cluster Autoscaler or a MachineSet Autoscaler powered by KEDA. The Cluster Autoscaler is a built-in, reactive tool that triggers scaling when pods enter a "Pending" state due to resource constraints. It is designed for general-purpose workloads and offers integrated safety features for pod eviction and scale-down operations.
Alternatively, KEDA enables proactive scaling by monitoring specific external metrics, such as PromQL queries or queue depths, allowing capacity to be added before pods fail to schedule. While KEDA provides finer control and faster trigger latency, it requires the installation of the Custom Metrics Autoscaler operator and lacks built-in pod safety checks during scale-down. These two systems cannot target the same MachineSet simultaneously without causing replica count instability, though they can coexist within the same cluster on separate MachineSets. The choice between them depends on whether the workload demand is signaled by pod scheduling pressure or by external performance metrics.
Full Take
This technical guide operates in CONSTRUCTIVE MODE, serving as a functional blueprint for infrastructure architects. It presents a classic engineering trade-off: the convenience of a native, reactive system versus the precision of a decoupled, proactive one. The strength of this analysis lies in its transparency regarding "trigger latency," admitting that while VM boot times are constant, the decision-making loop varies significantly between the two tools.
The underlying paradigm is one of delegation. Cluster Autoscaler delegates the "when" to the Kubernetes scheduler, prioritizing cluster stability and safety. KEDA delegates the "when" to external telemetry, prioritizing application performance and responsiveness. A generative question arises here: as we move toward more proactive, metric-driven scaling, do we risk introducing "phantom" costs where infrastructure scales based on noisy metrics rather than actual resource exhaustion?
Furthermore, the requirement that these tools cannot coexist on the same MachineSet suggests a rigid boundary in the control plane. A complementary angle to explore would be the development of a hybrid orchestrator capable of synthesizing both scheduler pressure and external metrics into a single scaling decision.
Bridge Questions:
1. If KEDA lacks built-in pod safety for scale-down, what application-level patterns are required to prevent data loss during node removal?
2. In what scenarios would the "step-by-step" growth of KEDA be inferior to the "one-shot" estimation of the Cluster Autoscaler?
Counterstrike Scan: If this were an influence campaign, it would likely use "Fear Appeal" by exaggerating the instability of reactive scaling to force a migration to complex third-party operators. The actual content is a neutral technical comparison; it is clean.
