Cloud & infrastructure

Kubernetes autoscalers conflict because they lack a unified control plane

Independent Kubernetes controllers like HPA, VPA, and KEDA often fight over the same resources, causing instability. A unified, autonomous approach is needed to resolve these conflicts.

Illustration of conflicting autoscaling signals represented by tangled wires and dials.
Illustration generated for this article

When site reliability engineers ask for the correct size of a service like checkout-api, they receive contradictory answers from their own infrastructure. Horizontal Pod Autoscaler (HPA) may demand eleven replicas due to CPU load, while Vertical Pod Autoscaler (VPA) claims the pods are over-provisioned. Simultaneously, KEDA requests twenty-four replicas to clear a Kafka backlog, and Karpenter adds new nodes based on inflated resource requests. This chaos occurs because five different controllers act logically in isolation, yet none possesses a complete view of the system’s actual needs.

What happened

Modern Kubernetes operations rely on a suite of specialized tools built on the Unix philosophy: small, modular components that perform single tasks well. HPA manages horizontal elasticity, VPA handles vertical sizing, KEDA bridges event sources to replica counts, and node autoscalers like Karpenter manage physical capacity. GitOps tools such as Argo CD enforce baseline states from version control. In traditional Unix pipelines, tools process data sequentially, passing immutable output from one stage to the next. However, Kubernetes autoscalers operate concurrently, mutating the same API fields such as .spec.replicas and .resources.requests without visibility into each other’s actions.

This architectural gap creates a situation where determining workload capacity becomes a fragmented process. Instead of solving a single coupled mathematical equation for optimal performance and cost, the system splits the problem across decoupled controllers. Each controller assumes exclusive control over its specific domain, leading to thrashing rather than efficiency. The result is a cluster where no single entity understands the trade-offs between latency, cost, and capacity, causing operational instability.

How it works

The conflict arises because independent control loops manipulate interdependent variables, creating four common failure modes. First, HPA and VPA collide through denominator collapse. HPA calculates target replicas by dividing actual usage by declared resource requests. When VPA lowers these requests to reduce waste, the denominator shrinks. Even minor traffic increases then push utilization percentages past HPA thresholds, triggering aggressive scale-out. As more pods share the load, per-pod usage drops, prompting VPA to shrink requests further, creating a death spiral of microscopic containers.

Second, native HPA and KEDA enter a multi-writer race condition. If an event queue spikes, KEDA scales up the deployment to drain the backlog. However, if the worker pods are I/O-heavy with low CPU usage, HPA sees low utilization and scales the deployment back down. The API server records alternating rescale events while actual processing throughput stalls. Third, GitOps engines create drift ping-pong. When HPA scales a deployment during a spike, GitOps tools flag the application as out of sync. If auto-sync is enabled, the system resets the deployment to its baseline, starving the application of capacity during peak demand.

Finally, node autoscalers amplify these inefficiencies. Tools like Karpenter provision physical instances based strictly on declared container requests, not actual consumption. If a container requests one CPU core but uses only 150 millicores, the scheduler reserves the entire core. This multiplies upstream sizing errors into massive cloud bills, leaving average cluster CPU utilization hovering around eight percent despite heavy provisioning.

Key details

  • Five distinct controllers (HPA, VPA, KEDA, Karpenter, GitOps) often provide contradictory sizing recommendations for the same workload.
  • HPA and VPA conflict because VPA reduces resource requests, which artificially inflates the utilization percentage used by HPA.
  • KEDA and HPA race to write to the same /scale sub-resource, causing oscillating replica counts when CPU usage does not match queue depth.
  • GitOps tools may revert dynamic scaling changes made by HPA, restoring baseline configurations that cannot handle current traffic loads.
  • Node autoscalers provision capacity based on declared requests rather than actual usage, leading to significant over-provisioning and low cluster utilization.
  • Current autoscalers function as automated reflexes lacking a central nervous system to coordinate their actions.

Why it matters

For software engineers and platform teams, these conflicts translate directly into unreliable services and inflated costs. The thrashing caused by competing controllers leads to latency spikes during demand surges, as reactive scaling waits for thresholds to be breached before acting. This reactive nature means that new compute resources are initialized only after performance has already degraded, violating service level objectives. Furthermore, the inability of GitOps to accurately reflect production reality breaks declarative infrastructure principles, making future rollouts risky and difficult to audit.

The financial impact is equally severe. Because node autoscalers rely on declared requests that are often inflated to prevent HPA-VPA conflicts, clusters run with vast amounts of unused capacity. Engineers spend significant time manually tuning thresholds and reconciling Git diffs instead of focusing on feature development. The lack of a unified control plane means that every scaling decision is a local optimization that may harm the global system state, preventing teams from achieving both cost efficiency and high availability simultaneously.

What you can do

  • Audit your cluster for concurrent controllers targeting the same resources, specifically checking for simultaneous HPA and VPA usage on the same deployments.
  • Evaluate whether GitOps auto-sync policies are reverting legitimate scaling events, and consider configuring ignore differences for replica counts carefully.
  • Monitor the ratio of declared resource requests to actual usage to identify where node autoscalers are provisioning excess capacity.
  • Consolidate scaling signals by using event-driven autoscaling exclusively for queue-based workloads, disabling CPU-based HPA for those specific services.
  • Implement predictive scaling strategies that analyze historical consumption patterns to pre-warm capacity before traffic spikes occur.
  • Seek solutions that offer a unified control plane capable of ingesting multiple signals and making joint decisions on horizontal and vertical sizing.
  • #kubernetes
  • #autoscaling
  • #devops
  • #cloud infrastructure
  • #sre

Tools from the Bytechap store

Keep reading

All stories