Developers

Kubernetes Autoscalers at War: Why Unified Control Beats Modular Chaos

Multiple independent autoscalers in Kubernetes create conflicting decisions that destabilize workloads. The industry needs a single, autonomous control plane that sees the complete picture.

6 min read
Why Kubernetes autoscalers keep fighting each other (and why the solution must be autonomous)

Pose a straightforward question to any site reliability engineer: What dimensions should checkout-api occupy, and how many instances must it maintain at this moment? The Helm configuration declares replicas: 3, cpu: 1000m, and memory: 2Gi. Yet the production environment reveals something entirely different: HPA has expanded the application to 11 replicas responding to CPU pressure; VPA simultaneously argues the workload is oversized, proposing cpu: 350m and memory: 3.1Gi; KEDA pushes for 24 replicas due to Kafka lag accumulation; and Karpenter has added two fresh nodes, allocating physical resources based on declared capacity rather than genuine demand.

Five sources yield five contradictory answers. Each controller acts logically in isolation, but none sees the complete picture.

This disconnect between isolated observations and actual application requirements exposes a fundamental architectural problem in contemporary Kubernetes deployments.

The breakdown of the Unix philosophy in elastic systems

Kubernetes emerged from the Unix philosophy: construct focused, single-purpose utilities that excel at one task. For orchestrating containers, this approach appeared logical:

  • HPA manages horizontal expansion based on observed resource consumption during runtime.
  • VPA manages vertical container adjustment based on past resource consumption patterns.
  • KEDA connects external event sources to replica decisions based on queue backlog.
  • Karpenter and Cluster Autoscaler provision node capacity when pods remain unscheduled.
  • GitOps (Argo CD / Flux) maintains baseline cluster configuration from version control.

In conventional Unix settings, utilities like grep and awk integrate smoothly because they process unchanging text sequences one after another. One operation completes and passes results to the subsequent step.

Autoscaling mechanisms operate differently. They function in parallel, targeting the same application and altering identical API fields: .spec.replicas, .resources.requests, and the node infrastructure. Each operates within its own independent loop, presuming sole authority over application sizing without awareness of neighboring systems.

Determining workload capacity is a single, coupled mathematical equation. Splitting it across decoupled controllers creates thrashing instead of modular efficiency.

The four collisions: how autoscalers fight

When separate control loops modify interconnected parameters, feedback mechanisms degrade into four typical failure patterns.

1. The denominator collapse: HPA vs. VPA

HPA computes desired replicas by dividing actual CPU consumption by the denominator of declared requests:

current metric = total actual usage / total declared requests

Declared resource requests form this denominator. When VPA runs in tandem, it reduces CPU requests to eliminate inefficiency. This shrinks the denominator. A modest traffic increase now pushes percentage utilization beyond HPA's limit, triggering rapid horizontal expansion. As additional pods distribute the traffic, per-pod consumption falls, causing VPA to compress requests further. The application spirals: VPA perpetually shrinks pod capacity while HPA spawns an uncontrollable swarm of tiny containers.

2. Multi-writer race condition: native HPA vs. KEDA

When organizations layer queue-driven scaling through KEDA atop standard CPU-based HPA, two separate controllers write to the same deployment's /scale sub-resource. An event queue surge causes KEDA to expand the deployment and consume the backlog. Yet if those worker pods perform I/O operations with minimal CPU demand, standalone HPA observes the low utilization, determines the app is over-resourced, and contracts it. The API server logs alternating resize commands while actual throughput processing stalls.

3. GitOps drift ping-pong: declarative IaC vs. dynamic runtime

GitOps platforms treat Git repositories as authoritative. When HPA expands a deployment during traffic surge, Argo CD marks the application as OutOfSync. With auto-sync active, GitOps reverts the live deployment to its declared baseline, depriving the application of resources during peak periods. Although teams frequently configure GitOps to disregard replica counts, this undermines declarative infrastructure: Git no longer mirrors production conditions, and future deployments risk silently restoring stale configurations.

4. The multiplier effect at the node layer

Node autoscalers such as Karpenter make allocation choices exclusively on declared container requests, ignoring genuine consumption. If a container declares 1000m CPU but consumes only 150m, the scheduler still holds the complete core. Karpenter acquires physical machines to satisfy fictitious demand, amplifying upstream sizing mistakes into substantial infrastructure expenses. Across production environments, typical cluster CPU utilization stays near 8% despite substantial node allocation.

The path to a better autoscaler

Each conventional autoscaler addresses a limited scope: "What should this individual parameter become?" The genuine operational challenge is more expansive: Which combination of replicas, resource requests, limits, and scaling parameters achieves latency SLOs at minimal expense, and when should that configuration shift?

Horizontal and vertical adjustment are interdependent elements of a unified optimization challenge. A genuine autoscaler cannot depend on responsive, single-metric approaches. It must operate as a coordinated control layer built on five essential functions:

  1. Unified signal ingestion: Processing CPU/memory metrics, queue depth, transaction rates, latency SLO compliance, node pricing, and IaC definitions concurrently.
  2. Joint decision-making: Generating a single action that specifies horizontal limits and vertical resource requests together, rather than delegating replicas to one system and pod sizing to another.
  3. Continuous GitOps synchronization: Submitting automated, justified pull requests to application repositories instead of requiring GitOps engines to disregard live cluster state, maintaining version control alignment with operational reality.
  4. Predictive and proactive capacity planning: Reactive scaling carries inherent flaws because provisioning fresh compute takes time. Conventional reactive systems wait for demand to exceed arbitrary thresholds, creating latency degradation during rapid load increases. A genuine autoscaler integrates forecasting methods to examine past consumption, recognize daily or weekly patterns, and anticipate workload demand. It pre-provisions application capacity and adjusts resources before traffic materializes, converting scaling from an emergency response into a coordinated, planned operation.
  5. Explainable auditing: Communicating transparent operational justification for each modification, granting SREs complete insight into trade-offs between cost reduction, anticipated demand, and latency constraints.

From reactive reflexes to true autonomy

The cloud-native sector frequently conflates "automated" with "autonomous."

Current autoscalers are automated: they behave like involuntary responses, detect an isolated measurement, and execute a predetermined action. When circumstances occur, HPA fires, KEDA expands, or Karpenter allocates. Yet involuntary responses lack a coordinating mechanism. When five separate reflexes activate simultaneously on the same structure, the system destabilizes.

Today's autoscalers are automated: they act like biological reflexes. But reflexes lack a central nervous system. When five independent reflexes fire simultaneously on the same limb, the system thrashes.

Genuine autonomy demands a feedback mechanism that examines the complete operational context, grasps the equilibrium between efficiency and expense, and maintains accountability for the complete outcome.

The Unix philosophy remains sound for the implementation layer: HPA, VPA, KEDA, and Karpenter should persist in performing the particular API operations they were engineered for. What Kubernetes presently lacks is the strategic intelligence layer that determines what those mechanisms should execute.

The next occasion your infrastructure team discusses whether to deploy HPA or VPA, reconsider and pose a deeper inquiry: Who determines this application's dimensions, and do they possess comprehensive visibility?

In contemporary deployments, nobody does. Addressing Kubernetes capacity optimization demands constructing a mechanism that ultimately does.

Source: The New Stack · Reporting supplemented by The Silicon Ledger staff.