science_health3254 wordsRead on Arc Codex

Red Hat OpenShift autoscaling with Cluster Autoscaler

There are different solutions for scaling your Red Hat OpenShift compute infrastructure, including: - Cluster Autoscaler: The built-in, Kubernetes-native approach, integrated with the Red Hat OpenShift machine API. - MachineSet Autoscaler with a custom autoscaler (KEDA): A metrics-driven approach that scales individual MachineSets based on external or custom signals. This article examines Cluster Autoscaler, with an example on Microsoft Azure Red Hat OpenShift. The next article in this series covers a KEDA-based MachineSet Autoscaler driven by Prometheus CPU utilization, and a third article compares both approaches. Cluster Autoscaler in Red Hat OpenShift Cluster Autoscaler automatically adjusts the size of an Red Hat OpenShift Container Platform cluster to meet current workload demands. It is based on the upstream Cluster Autoscaler project and is integrated with OpenShift through the ClusterAutoscalerOperator, which exposes 2 custom resources: ClusterAutoscaler - API: autoscaling.openshift.io/v1 - Scope: Cluster-wide - Role: Decides when and how much to scale, enforces global limits MachineAutoscaler - API: autoscaling.openshift.io/v1beta1 - Scope: Per MachineSet - Role: Defines which MachineSets can scale and their minimum and maximum bounds. Both resources are required. The Cluster Autoscaler alone cannot scale anything. It relies on MachineAutoscaler resources to annotate eligible MachineSets and to define per–MachineSet replica boundaries. If you deploy a ClusterAutoscaler without any MachineAutoscaler objects, the cluster never scales. How it works Cluster Autoscaler is only available on clusters where the Machine API operator is operational (installer-provisioned infrastructure on supported cloud providers). Scale-up trigger By default, Cluster Autoscaler increases cluster size when: - Pods remain Pending because no worker node has sufficient CPU, memory, or other schedulable resources. - A pod cannot be scheduled due to constraints (node selectors, affinity, taints) that require an additional node of a specific type. That pending-pod path is the classic, always-on behavior demonstrated in this article. Cluster Autoscaler also supports predictive and proactive scale-up using 2 APIs: - ProvisioningRequest: Request capacity for a group of pods before (or as part of) admitting the workload (for example, gang provisioning with Kueue). - CapacityBuffer: Declare spare capacity that the autoscaler treats as demand, so nodes can be pre-provisioned ahead of real workloads. In the pending-pod path, the autoscaler only adds nodes when doing so would result in a schedulable pod. It does not scale up if: - Available MachineSet node types cannot satisfy the pod's resource or constraint requirements. - All eligible MachineSets are already at their maxReplicas limit. - Global ClusterAutoscaler limits (cores, memory, GPUs,maxNodesTotal ) would be exceeded. Scale-down behavior Every 10 seconds, the Cluster Autoscaler evaluates whether any worker nodes are unnecessary and can be removed. A node is eligible for removal when: - Utilization is below the threshold: Node utilization level (sum of requested resources divided by node allocatable resources) is less than the configured utilization threshold (default is 0.5 , which is 50%). - All pods can be rescheduled elsewhere by the Kubernetes scheduler. - The node does not have the scale-down disabled annotation. The autoscaler does not remove a node that hosts: - Pods with restrictive PodDisruptionBudgets (PDBs). kube-system pods that are not normally present on worker nodes, or that lack an appropriate PDB.- Pods not owned by a controller (Deployment, ReplicaSet, StatefulSet, and so on). - Pods with local storage. - Pods that cannot be moved (insufficient cluster capacity, anti-affinity conflicts, incompatible selectors). - Pods annotated with cluster-autoscaler.kubernetes.io/safe-to-evict: "false" (unless also markedsafe-to-evict: "true" ). Resource accounting To align with the cluster scheduling logic, the Cluster Autoscaler relies on allocatable capacity (status.allocatable ) rather than total raw node resources when checking pod scheduling feasibility or verifying global ClusterAutoscaler resourceLimits (cores.min/max, memory.min/max ). By doing so, it successfully includes system constraints and kubelet reservations in scale-up decisions and threshold validations. Resource metrics (CPU, memory, and GPU) are collected from all cluster elements, including control plane nodes, even though the autoscaler does not control those specific MachineSets. Global limits are checked against this cumulative, cluster-wide allocatable pool instead of being restricted to single MachineSets. When choosing which MachineSet to expand, the autoscaler uses an expander strategy: Random : By default, selects a MachineSet at randomLeastWaste : Minimizes idle CPU (then memory) after scalingPriority : Uses a ConfigMap with regex patterns to prefer higher-priority MachineSets Limitations When using Cluster Autoscaler, keep these constraints in mind: - Avoid making manual changes to individual nodes within an autoscaled MachineSet, because system pods, labels, and total capacity are shared equally across all nodes in the group. - Always specify resource requests on pods; the autoscaler uses requests (not limits) for scheduling simulation. - Configure PDBs for workloads that must not be evicted during scale-down. - Ensure cloud provider quotas support the maximum node counts configured. - Do not run additional cloud-provider node group autoscalers alongside Cluster Autoscaler. - Set maxNodesTotal large enough to cover control plane machines plus all possible compute machines across everyMachineAutoscaler . Example: Microsoft Azure Red Hat OpenShift cluster (scaling eastus3 from 1 to 3) The following example was built and verified on an OpenShift 4.20 cluster deployed with installer-provisioned infrastructure on Microsoft Azure. Cluster inventory Microsoft Azure virtual machine sizes and allocatable resources (status.allocatable ) reported on demo-p4p95 : Control plane - Azure VM size: Standard_D8s_v3 - Count: 3 (fixed) - CPU: 7500m - Memory: 30.2 GiB Worker - Azure VM size: Standard_D4s_v3 - Count: 3 → 5 (2 fixed + 1–3 eastus3) - CPU: 3500m - Memory: 14.5 GiB ClusterAutoscaler resourceLimits calculate total available CPU and memory across every node, including the control plane. For unprovisioned nodes, the Cluster Autoscaler relies on capacity annotations from the MachineAutoscaler operator. Worker MachineSets at install time: NAME DESIRED CURRENT READY AVAILABLE demo-p4p95-worker-eastus1 1 1 1 1 demo-p4p95-worker-eastus2 1 1 1 1 demo-p4p95-worker-eastus3 1 1 1 1 Raw allocatable values from the cluster: $ kubectl get nodes -o \ custom-columns=NAME:.metadata.name,CPU:.status.allocatable.cpu,MEMORY:.status.allocatable.memory NAME CPU MEMORY demo-p4p95-master-0 7500m 31706428Ki demo-p4p95-worker-eastus3-xpnp4 3500m 15216988Ki Converted to GiB (Ki ÷ 1024²), each master is about 30.2 GiB, and each worker is about 14.5 GiB. MachineAutoscaler capacity annotations on demo-p4p95-worker-eastus3 (used to simulate hypothetical nodes during scale-up decisions): { "capacity.cluster-autoscaler.kubernetes.io/cpu": "4", "capacity.cluster-autoscaler.kubernetes.io/memory": "17179869184", "capacity.cluster-autoscaler.kubernetes.io/labels": "kubernetes.io/arch=amd64,topology.kubernetes.io/zone=eastus-3", "capacity.cluster-autoscaler.kubernetes.io/taints": "machineset-autoscaler/demo=eastus3:NoSchedule" } Nodes in this MachineSet carry taint machineset-autoscaler/demo=eastus3:NoSchedule so only the scale-test workload schedules there (Step 4). Sizing the limits The cluster baseline has 6 nodes (3 masters + 2 fixed workers + 1 eastus3 worker). Scaling eastus3 from 1 to 3 adds up to 2 more nodes. For hypothetical nodes (not yet provisioned), the CA uses capacity annotations (raw vCPU: 4 per worker) rather than allocatable (3.5): maxNodesTotal - Calculation: 3 masters + 2 fixed + 3 eastus3 - Value: 8 cores.min - Calculation: (3 × 7.5) + (3 × 3.5) - Value: 33 cores.max - Calculation: 33 + (2 × 4) ← capacity annotation - Value: 44 memory.min - Calculation: (3 × 30.2) + (3 × 14.5) GiB - Value: 134 GiB memory.max - Calculation: 134 + (2 × 16) GiB ← capacity annotation - Value: 170 GiB In the custom resource (CR), cores values are whole numbers, so 7500m equals 7.5 cores and 3500m equals 3.5 cores. memory values are measured in GiB. For hypothetical nodes, the CA uses the capacity.cluster-autoscaler.kubernetes.io/cpu annotation (raw 4 vCPU) rather than actual allocatable. Only demo-p4p95-worker-eastus3 gets a MachineAutoscaler . The other 2 MachineSets remain at their fixed replica counts: | MachineSet | minReplicas | maxReplicas | Rationale | |---|---|---|---| | demo-p4p95-worker-eastus1 | — | — | Fixed at 1 (no MachineAutoscaler) | | demo-p4p95-worker-eastus2 | — | — | Fixed at 1 (no MachineAutoscaler) | | demo-p4p95-worker-eastus3 | 1 | 3 | Elastic target: scales 1 → 3 (zone 3) | Step 1: Deploy the ClusterAutoscaler Here is the cluster-autoscaler.yaml : apiVersion: autoscaling.openshift.io/v1 kind: ClusterAutoscaler metadata: name: default spec: resourceLimits: maxNodesTotal: 8 cores: min: 33 max: 44 memory: min: 134 max: 170 scaleDown: enabled: true delayAfterAdd: 5m delayAfterDelete: 2m delayAfterFailure: 30s unneededTime: 3m utilizationThreshold: "0.5" scaleUp: newPodScaleUpDelay: 10s expanders: - Random Apply it with kubectl : kubectl apply -f cluster-autoscaler.yaml Step 2: Deploy MachineAutoscaler for eastus3 The machine-autoscaler-worker-eastus3.yaml allows zone 3 to scale from 1 to 3 nodes: apiVersion: autoscaling.openshift.io/v1beta1 kind: MachineAutoscaler metadata: name: demo-p4p95-worker-eastus3 namespace: openshift-machine-api spec: minReplicas: 1 maxReplicas: 3 scaleTargetRef: apiVersion: machine.openshift.io/v1beta1 kind: MachineSet name: demo-p4p95-worker-eastus3 Apply it with kubectl : kubectl apply -f machine-autoscaler-worker-eastus3.yaml Step 3: Add capacity label annotation (required for zone affinity on hypothetical nodes) The Cluster Autoscaler evaluates adding a new node to satisfy zone-affinity pods, but it must know what labels that hypothetical node would carry. The MachineAutoscaler operator sets capacity.cluster-autoscaler.kubernetes.io/cpu and /memory automatically, but the zone label must be added explicitly: kubectl annotate machineset demo-p4p95-worker-eastus3 -n openshift-machine-api \ "capacity.cluster-autoscaler.kubernetes.io/labels=kubernetes.io/arch=amd64,topology.kubernetes.io/zone=eastus-3" \ --overwrite Without this annotation, Cluster Autoscaler logs No expansion options because it cannot determine that the new node would satisfy the pod's zone affinity constraint. Step 4: Taint eastus3 workers (dedicated pool for scale tests) Add a NoSchedule taint on the MachineSet so only workloads with a matching toleration can land on eastus3 nodes. System daemons (with their own tolerations) still run; general application pods stay off this pool. Here's the machineset-worker-eastus3-taints-patch.yaml file: spec: template: spec: taints: - key: machineset-autoscaler/demo value: eastus3 effect: NoSchedule Apply it with kubectl : kubectl patch machineset demo-p4p95-worker-eastus3 -n openshift-machine-api \ --type merge --patch-file samples/machineset-worker-eastus3-taints-patch.yaml Taints on the MachineSet template apply to new machines only. Patch existing Machine objects (or run samples/machineset-worker-eastus3-apply-taints.sh ) so nodes already in the cluster pick up the taint. For Cluster Autoscaler scale-up simulation, annotate taints on hypothetical nodes: kubectl annotate machineset demo-p4p95-worker-eastus3 -n openshift-machine-api \ "capacity.cluster-autoscaler.kubernetes.io/taints=machineset-autoscaler/demo=eastus3:NoSchedule" \ --overwrite Without the taints annotation, Cluster Autoscaler may not expand the group for pods that tolerate the taint but have no other matching node. Step 5: Verify deployment Verify your deployment: kubectl get clusterautoscaler kubectl get machineautoscaler -n openshift-machine-api Output from demo-p4p95 : NAME AGE default 2s NAME REF KIND REF NAME MIN MAX AGE demo-p4p95-worker-eastus3 MachineSet demo-p4p95-worker-eastus3 1 3 3s The MachineAutoscaler operator annotates the target MachineSet immediately: { "machine.openshift.io/cluster-api-autoscaler-node-group-min-size": "1", "machine.openshift.io/cluster-api-autoscaler-node-group-max-size": "3", "capacity.cluster-autoscaler.kubernetes.io/cpu": "4", "capacity.cluster-autoscaler.kubernetes.io/memory": "17179869184", "capacity.cluster-autoscaler.kubernetes.io/labels": "kubernetes.io/arch=amd64,topology.kubernetes.io/zone=eastus-3", "capacity.cluster-autoscaler.kubernetes.io/taints": "machineset-autoscaler/demo=eastus3:NoSchedule" } Step 6: Trigger scale-up with a test workload The scale test runs in a dedicated test namespace. The test-namespace.yaml file: apiVersion: v1 kind: Namespace metadata: name: test labels: app.kubernetes.io/part-of: machineset-autoscaler-demo Pods are restricted to zone eastus-3 and tolerate the eastus3 MachineSet taint (machineset-autoscaler/demo=eastus3:NoSchedule ). The scale-test-deployment.yaml configuration deploys 9 replicas in the test namespace, each requesting 1 CPU. With 1 eastus3 worker (3.5 allocatable CPU), zone affinity, and the taint in place, 3 pods fit on the existing node and 6 remain Pending: apiVersion: apps/v1 kind: Deployment metadata: name: cluster-autoscaler-scale-test namespace: test labels: app: cluster-autoscaler-scale-test spec: replicas: 9 selector: matchLabels: app: cluster-autoscaler-scale-test template: metadata: labels: app: cluster-autoscaler-scale-test spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - eastus-3 tolerations: - key: machineset-autoscaler/demo operator: Equal value: eastus3 effect: NoSchedule containers: - name: pause image: registry.access.redhat.com/ubi9/ubi-minimal:latest command: ["sleep", "infinity"] resources: requests: cpu: "1" memory: 512Mi Apply with kubectl : kubectl apply -f test-namespace.yaml kubectl apply -f scale-test-deployment.yaml kubectl get pods -n test -l app=cluster-autoscaler-scale-test The result: NAME READY STATUS NODE cluster-autoscaler-scale-test-8657c6c5f6-7gf89 1/1 Running demo-p4p95-worker-eastus3-xpnp4 cluster-autoscaler-scale-test-8657c6c5f6-8lmmd 1/1 Running demo-p4p95-worker-eastus3-xpnp4 cluster-autoscaler-scale-test-8657c6c5f6-9vj4g 1/1 Running demo-p4p95-worker-eastus3-xpnp4 cluster-autoscaler-scale-test-8657c6c5f6-hqd7f 0/1 Pending cluster-autoscaler-scale-test-8657c6c5f6-hr88x 0/1 Pending cluster-autoscaler-scale-test-8657c6c5f6-jwd7q 0/1 Pending cluster-autoscaler-scale-test-8657c6c5f6-pbnj2 0/1 Pending cluster-autoscaler-scale-test-8657c6c5f6-sk276 0/1 Pending cluster-autoscaler-scale-test-8657c6c5f6-tvcn4 0/1 Pending Scheduler events on pending pods confirm insufficient capacity on the existing node: Warning FailedScheduling default-scheduler 0/6 nodes are available: 1 Insufficient cpu, 1 node(s) had untolerated taint {machineset-autoscaler/demo: eastus3}, 1 node(s) didn't match Pod's node affinity/selector, 3 node(s) had untolerated taint {node-role.kubernetes.io/master: }. Verification: Cluster Autoscaler working Follow these steps to verify that autoscaling is working as expected. 1. Cluster Autoscaler detected unschedulable pods and initiated scale-up With 1 eastus3 node already running, 3 pods scheduled immediately and 6 remained Pending. Cluster Autoscaler detected the unschedulable pods and scaled up: I0701 22:15:42.437401 orchestrator.go:185] Best option to resize: MachineSet/openshift-machine-api/demo-p4p95-worker-eastus3 I0701 22:15:42.437429 orchestrator.go:189] Estimated 2 nodes needed in MachineSet/openshift-machine-api/demo-p4p95-worker-eastus3 I0701 22:15:42.437477 orchestrator.go:261] Final scale-up plan: [{MachineSet/openshift-machine-api/demo-p4p95-worker-eastus3 1->3 (max: 3)}] I0701 22:15:42.437500 executor.go:164] Scale-up: setting group MachineSet/openshift-machine-api/demo-p4p95-worker-eastus3 size to 3 2. Kubernetes events recorded the scale-up decision Proof that Kubernetes events have recorded the scale-up decision: LAST SEEN TYPE REASON MESSAGE 8m Normal ScaledUpGroup Scale-up: setting group MachineSet/openshift-machine-api/demo-p4p95-worker-eastus3 size to 3 instead of 1 (max: 3) 3. MachineSet replica count increased, and Azure provisioned 2 additional VMs Before (1 eastus3 worker): NAME DESIRED CURRENT READY AVAILABLE demo-p4p95-worker-eastus3 1 1 1 1 After (3 eastus3 workers, max reached): NAME DESIRED CURRENT READY AVAILABLE demo-p4p95-worker-eastus3 3 3 3 3 Machines in Azure zone 3: NAME PHASE TYPE REGION ZONE demo-p4p95-worker-eastus3-xpnp4 Running Standard_D4s_v3 eastus 3 demo-p4p95-worker-eastus3-tvgkf Running Standard_D4s_v3 eastus 3 demo-p4p95-worker-eastus3-ntmd9 Running Standard_D4s_v3 eastus 3 4. New worker nodes joined the cluster Verify that new worker nodes have joined the cluster: NAME STATUS ROLES AGE demo-p4p95-worker-eastus3-xpnp4 Ready worker 63m (existing) demo-p4p95-worker-eastus3-tvgkf Ready worker 10m demo-p4p95-worker-eastus3-ntmd9 Ready worker 4m All 9 pods scheduled across the 3 nodes (3 pods per node): cluster-autoscaler-scale-test-8657c6c5f6-7gf89 Running demo-p4p95-worker-eastus3-xpnp4 cluster-autoscaler-scale-test-8657c6c5f6-8lmmd Running demo-p4p95-worker-eastus3-xpnp4 cluster-autoscaler-scale-test-8657c6c5f6-9vj4g Running demo-p4p95-worker-eastus3-xpnp4 cluster-autoscaler-scale-test-8657c6c5f6-hqd7f Running demo-p4p95-worker-eastus3-tvgkf cluster-autoscaler-scale-test-8657c6c5f6-hr88x Running demo-p4p95-worker-eastus3-tvgkf cluster-autoscaler-scale-test-8657c6c5f6-jwd7q Running demo-p4p95-worker-eastus3-tvgkf cluster-autoscaler-scale-test-8657c6c5f6-pbnj2 Running demo-p4p95-worker-eastus3-ntmd9 cluster-autoscaler-scale-test-8657c6c5f6-sk276 Running demo-p4p95-worker-eastus3-ntmd9 cluster-autoscaler-scale-test-8657c6c5f6-tvcn4 Running demo-p4p95-worker-eastus3-ntmd9 5. Cluster Autoscaler status reports healthy state at max capacity From the cluster-autoscaler-status ConfigMap in openshift-machine-api : autoscalerStatus: Running clusterWide: health: status: Healthy nodeCounts: registered: total: 8 ready: 8 scaleUp: status: NoActivity nodeGroups: - name: MachineSet/openshift-machine-api/demo-p4p95-worker-eastus3 cloudProviderTarget: 3 minSize: 1 maxSize: 3 All 9 pods Running because the MachineSet reached 3 nodes (the maximum). The timeline: - T+0s: Deployed 9 pods (1 CPU each, zone eastus-3) — 3 Running, 6 Pending - T+~10m: Cluster Autoscaler detected 6 unschedulable pods, scaled MachineSet 1 → 3 - T+~17m: Second node ready — 3 more pods Running (6 total) - T+~24m: Third node ready — last 3 pods Running - T+~24m: All 9 pods Running — scale-up complete Cleanup Remember to clean up ClusterAutoscaler and MachineAutoscaler resources previously created to avoid any issue when testing other alternatives. kubectl delete -f scale-test-deployment.yaml After scaleDown delays elapse, eastus3 workers scale back to minReplicas (1) automatically. Summary of Cluster Autoscaler characteristics - Trigger: Unschedulable pods by default. Also ProvisioningRequest and CapacityBuffer for predictive capacity. - Signal: Kubernetes scheduler simulation (plus ProvReq / buffer demand) not arbitrary external metrics. - Scope: Cluster-wide limits, per–MachineSet bounds with MachineAutoscaler. - Scale-down: Automatic, based on node utilization and pod eviction safety. - Integration: Native OpenShift CRDs, with no additional operators required. - Best for: General-purpose capacity management driven by pod scheduling pressure (with optional predictive APIs). Limitation: Reactive scaling and node boot time In the default path, Cluster Autoscaler is reactive. It requests a new node after a pod is already Pending and the scheduler confirms it cannot be placed on any existing node (predictive alternatives ProvisioningRequest and CapacityBuffer are covered in the next section). That decision itself is fast. On demo-p4p95 , the autoscaler detected 6 unschedulable pods and increased the eastus3 MachineSet replica count within ~10 minutes of deployment, but provisioning the VM and joining it to the cluster takes much longer. The end-to-end delay is the sum of several steps (read Cluster Autoscaler FAQ: How fast is HPA when combined with CA? for more information): HPA reaction (if used) - Duration: ~30 s – 3 min - Metrics scrape interval, backoff. Cluster Autoscaler reaction - Duration: ~10 s (default) - Configurable with scaleUp.newPodScaleUpDelay . Cloud VM provisioning - Duration: 3 – 7+ min - Provider-dependent. On demo-p4p95 (AzureStandard_D4s_v3 ) each new eastus3 worker took ~7 min from scale-up request to Ready. Pod scheduling on new node - Duration: ~10 – 30 s - After the node registers and passes readiness checks. Workload pods stay Pending during the provisioning process. For latency-sensitive or bursty workloads, this wait is often too long, even when autoscaling is configured correctly. Pending pod detected │ ▼ ~10 s Cluster Autoscaler increases MachineSet replicas │ ▼ 3–7+ min (cloud provider + new node preparation) New VM provisioned, node joins cluster │ ▼ ~10–30 s Pending pods scheduled on new node Mitigation: Overprovisioning with pause pods A common solution is overprovisioning: running low-priority pause pods to hold extra CPU and memory in reserve. When real workloads arrive, they displace the pause pods. The pause pods then move to a Pending state, triggering Cluster Autoscaler to add nodes before production workloads suffer delays. This pattern is documented in the Cluster Autoscaler FAQ. The essential pieces are: - A PriorityClass with a low value (for example, -10 ) set for overprovisioning pods, live workloads can preempt them without issue. The value remains high enough to add nodes when the pause pods cannot run elsewhere. - A Deployment of pause containers ( registry.k8s.io/pause ) with resource requests matching the headroom you want to keep warm. - Optionally, a Cluster Proportional Autoscaler to adjust pause-pod replicas dynamically as the cluster grows or shrinks (for example, keep one pause pod per N cores). Minimal static example: apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: overprovisioning value: -10 globalDefault: false description: "Priority class used by overprovisioning." --- apiVersion: apps/v1 kind: Deployment metadata: name: overprovisioning namespace: default spec: replicas: 1 selector: matchLabels: run: overprovisioning template: metadata: labels: run: overprovisioning spec: priorityClassName: overprovisioning terminationGracePeriodSeconds: 0 containers: - name: reserve-resources image: registry.k8s.io/pause:3.9 resources: requests: cpu: "1" memory: 512Mi Increasing replicas or per-pod requests reserves more headroom and tends to keep more nodes online ahead of demand. Side effects of overprovisioning Overprovisioning trades cost and complexity for lower scheduling latency: - Higher baseline cost: Nodes run idle pause containers that consume allocatable resources you pay for but do not use productively - Artificial cluster size: The cluster may hold more nodes than current workloads require, reducing scale-down opportunities - Priority preemption required: Real workloads must use a higher PriorityClass than pause pods (≥ 0 compared to -10) or they cannot displace the placeholders - Operational overhead: Static sizing is simple but inflexible; dynamic sizing adds the Cluster Proportional Autoscaler and tuning of ratios - Misconfiguration risk: Too much overprovisioning wastes money; too little leaves the same Pending delay as before Overprovisioning does not change how Cluster Autoscaler works. It simply changes when scaling triggers by keeping placeholder pods pending before production traffic arrives. Predictive scaling with ProvisioningRequest and CapacityBuffer Pending pods and pause-pod overprovisioning are not the only ways to drive Cluster Autoscaler. Upstream CA (and OpenShift's integration of it) also expose APIs that request capacity before production pods become unschedulable: ProvisioningRequest (autoscaling.x-k8s.io ) - Role: Ask Cluster Autoscaler for capacity for a group of pods (check-capacity or best-effort atomic scale-up). Often used with Kueue for gang admission: capacity is provisioned (or confirmed) before the job is admitted. - OpenShift status (standalone): Developer Preview, enable with featureSet: DevPreviewNoUpgrade CapacityBuffer (autoscaling.x-k8s.io ) - Role: Declare spare capacity (fixed or proportional to a scalable target). A controller turns the buffer into virtual or fake pods that Cluster Autoscaler treats as demand, so nodes can stay warm without managing pause Deployments by hand. - OpenShift status (standalone): Emerging upstream CA API; availability on a given OpenShift release depends on the Cluster Autoscaler build. These APIs handle scaling decisions directly within Cluster Autoscaler's scheduler simulation. While they are not a substitute for PromQL or business metrics, they enable predictive capacity requests and offer a cleaner spare-capacity model than traditional pause pods. For gang-style AI/ML flows on OpenShift, see Gang autoscaling on OpenShift with Kueue and ProvisioningRequest. Why consider a different approach? Cluster Autoscaler triggers scale-ups based on scheduling pressure, even when using overprovisioning. It does not read queue depth or business metrics like KEDA does. ProvisioningRequest and CapacityBuffer help cut down wait times for pending workloads, but metric-based MachineSet scaling remains essential when you want to scale on resource utilization, queue length, or external systems.

How it works

Once you click Generate, Ollama reads this article and crafts 5 comprehension questions. Your answers are graded against the article content — general knowledge won't be enough. Score 70+ to count toward your certificate.

Questions are cached — you'll always get the same 5 for this article.