Why Kubernetes autoscalers keep fighting each other (and why the solution must be autonomous)
記事本文
25 段落 · 単語をタップ(クリック)または文章を選ぶと翻訳 · 単語をタップ/文章を選ぶと翻訳Ask an SRE a deceptively simple question: What is the right size for checkout-api, and how many replicas should it run right now?
Their Helm values specify replicas: 3, cpu: 1000m, and memory: 2Gi. But the live cluster tells a different story: HPA has scaled the app to 11 replicas on CPU load; VPA insists it is over-provisioned, recommending cpu: 350m and memory: 3.1Gi; KEDA demands 24 replicas due to an upstream Kafka lag spike; and Karpenter has provisioned two new nodes, sizing physical capacity strictly against declared requests rather than actual usage.
“Five sources yield five contradictory answers. Each controller acts logically in isolation, but none sees the complete picture.”
Five sources yield five contradictory answers. Each controller acts logically in isolation, but none sees the complete picture. This gap between isolated observations and actual workload needs represents a core architectural failure in modern Kubernetes operations.
Kubernetes and its components were built on the Unix philosophy: build small, modular tools that do one thing well. For container orchestration, this principle seemed intuitive:
In standard Unix environments, tools like grep and awk compose cleanly because they process immutable streams of text sequentially. One tool finishes and hands its output to the next.
Autoscaling controllers do not operate sequentially. They execute concurrently, acting on the same target workload and mutating the same API fields: .spec.replicas, .resources.requests, and the underlying node pool. Each runs in an independent reconciliation loop, assuming exclusive control over workload sizing without visibility into adjacent tools.
“Determining workload capacity is a single, coupled mathematical equation. Splitting it across decoupled controllers creates thrashing instead of modular efficiency.”
Determining workload capacity is a single, coupled mathematical equation. Splitting it across decoupled controllers creates thrashing instead of modular efficiency.
When independent control loops manipulate interdependent variables, feedback loops destabilize into four common failure modes.
HPA calculates target replicas using pod CPU utilization as a percentage of declared requests:
current metric = total actual usage / total declared requests
Declared resource requests serve as the denominator. When VPA operates concurrently, it lowers CPU requests to eliminate waste. This shrinks the denominator. A minor traffic increase now pushes percentage utilization past HPA’s threshold, triggering an aggressive horizontal scale-out. As more pods split the traffic, per-pod usage drops, prompting VPA to shrink requests even further. The workload enters a death spiral: VPA continuously shrinks pod size while HPA creates an unmanageable fleet of microscopic containers.
When teams combine queue-based scaling via KEDA with standard CPU-based HPA, two controllers target the same deployment’s /scale sub-resource. If an event queue spikes, KEDA scales the deployment up to drain the backlog. However, if those worker pods are I/O-heavy with low CPU usage, the standalone HPA evaluates the low utilization, concludes the app is over-provisioned, and scales it back down. The API server records alternating rescale events while actual processing throughput stalls.
GitOps engines enforce Git repositories as the source of truth. When HPA scales a deployment during a traffic spike, Argo CD flags the application as OutOfSync. If auto-sync is enabled, GitOps resets the live deployment back to its baseline, starving the application of capacity during peak demand. While engineers often configure GitOps to ignore replica differences, this breaks declarative infrastructure: Git no longer reflects production reality, and future rollouts risk quietly restoring outdated baselines.
Node autoscalers like Karpenter make placement decisions based strictly on declared container requests, not actual consumption. If a container requests 1000m CPU but consumes only 150m, the scheduler still reserves the entire core. Karpenter provisions physical instances to satisfy phantom demand, multiplying upstream sizing inefficiencies into massive cloud bills. Across production fleets, average cluster CPU utilization hovers around 8% despite heavy node provisioning.
Every traditional autoscaler answers a narrow question: “What should my individual setting be?” But the real operational requirement is broader: What combination of replicas, resource requests, limits, and scaling thresholds satisfies latency SLOs at the lowest cost, and when should that configuration change?
Horizontal and vertical sizing are interlinked variables of a single optimization problem. A true autoscaler cannot rely on reactive, single-metric heuristics. It must function as a unified control plane defined by five core capabilities:
The cloud-native ecosystem routinely conflates “automated” and “autonomous.”
Today’s autoscalers are automated: they act like biological reflexes, measure an isolated telemetry signal, and fire a predefined response. When an event occurs, HPA triggers, KEDA scales, or Karpenter provisions. But reflexes lack a central nervous system. When five independent reflexes fire simultaneously on the same limb, the system thrashes.
“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.”
Autonomy requires a closed loop that observes the entire operating environment, understands the tradeoffs between performance and cost, and assumes end-to-end accountability for the outcome.
The Unix philosophy remains the right blueprint for the execution layer: HPA, VPA, KEDA, and Karpenter should continue executing the specific API mutations they were designed to handle. What Kubernetes fundamentally lacks is the central intelligence layer that decides what those actuators should do.
The next time your platform team debates whether to implement HPA or VPA, step back and ask a broader question: Who decides this workload’s size, and do they have the full picture?
In modern clusters, nobody does. Solving Kubernetes rightsizing requires building a system that finally does.
段落ごとの訳がずれるときに
全文翻訳
単語をタップ(クリック)すると単語を、文章を選ぶとその範囲をすぐに翻訳します。