Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Kubernetes Autoscaling: HPA, VPA and Cluster Autoscaler

By Kokil Thapa | Last reviewed: August 2026

Configuring Kubernetes Autoscaling: HPA, VPA and Cluster Autoscaler correctly is the difference between a resilient platform and an unpredictable billing nightmare. While many developers treat these as interchangeable scaling tools, they solve fundamentally different problems at distinct layers of the infrastructure stack. Misunderstanding their boundaries leads to resource contention, failed deployments, or massive over-provisioning that drains budgets faster than traffic spikes can justify.

For teams managing production workloads, especially those transitioning from traditional VPS setups or exploring cloud migration strategies, understanding this separation of concerns is non-negotiable. You cannot simply enable all three and expect harmony; without explicit coordination policies, VPA will fight HPA, and both will trigger erratic Cluster Autoscaler behaviour. This guide breaks down exactly how each component functions in 2026, where they overlap, and how to configure them safely for real-world applications ranging from Laravel APIs to high-throughput data processors.

How does Horizontal Pod Autoscaler (HPA) handle traffic-driven scaling?

The Horizontal Pod Autoscaler is the most mature and widely used component of the Kubernetes autoscaling triad. Its job is singular: adjust the number of pod replicas in a Deployment, StatefulSet, or ReplicaSet based on observed metrics. In practice, HPA excels at handling predictable and unpredictable traffic patterns for stateless services where adding more identical instances linearly increases throughput.

Core mechanics and metric sources

HPA operates on a control loop that queries the Metrics API every 15 seconds by default. It supports two primary metric types:

  • Resource Metrics: CPU and memory utilization relative to the pod's requested resources. This requires the Metrics Server to be installed and healthy.
  • Custom/External Metrics: Application-specific signals like queue depth, HTTP requests per second, or database connection pool saturation. These require the Custom Metrics API or External Metrics API adapter (e.g., Prometheus Adapter).

A common mistake I see on client projects is setting HPA targets based on limits rather than requests. HPA calculates utilization as currentValue / request. If your pod requests 250m CPU but has a 1000m limit, hitting 500m actual usage shows 200% utilization against the request, triggering aggressive scale-up even though you are only at 50% of the limit. Always tune requests to reflect true baseline consumption before configuring HPA thresholds.

PodsCPU / Memory / CustomMetrics APIAggregated MetricsHPA ControllerScale DecisionAdjust Replica Count
HPA control loop: metrics flow from pods through the Metrics API to the HPA controller, which adjusts replica counts and closes the feedback loop

Practical HPA configuration for 2026

Modern HPA manifests use autoscaling/v2 API version. Here is a production-ready example for a Laravel queue worker scaled by custom RabbitMQ queue length:

<!-- apiVersion: autoscaling/v2 -->
<!-- kind: HorizontalPodAutoscaler -->
<!-- metadata: -->
<!--   name: laravel-queue-worker-hpa -->
<!-- spec: -->
<!--   scaleTargetRef: -->
<!--     apiVersion: apps/v1 -->
<!--     kind: Deployment -->
<!--     name: laravel-queue-worker -->
<!--   minReplicas: 2 -->
<!--   maxReplicas: 20 -->
<!--   metrics: -->
<!--     - type: External -->
<!--       external: -->
<!--         metric: -->
<!--           name: rabbitmq_queue_messages -->
<!--           selector: -->
<!--             matchLabels: -->
<!--               queue: invoice-processing -->
<!--         target: -->
<!--           type: AverageValue -->
<!--           averageValue: "50" -->
<!--   behavior: -->
<!--     scaleUp: -->
<!--       stabilizationWindowSeconds: 30 -->
<!--       policies: -->
<!--         - type: Pods -->
<!--           value: 4 -->
<!--           periodSeconds: 60 -->
<!--     scaleDown: -->
<!--       stabilizationWindowSeconds: 300 -->
<!--       policies: -->
<!--         - type: Pods -->
<!--           value: 2 -->
<!--           periodSeconds: 120 -->

The behavior block is critical. Without it, HPA uses legacy defaults that scale up aggressively but scale down too slowly (or vice versa depending on version). Setting a 5-minute stabilization window for scale-down prevents flapping when traffic has natural valleys. For eCommerce platforms processing seasonal bursts during Dashain or Black Friday, this damping prevents premature termination of workers mid-job.

When should you use Vertical Pod Autoscaler instead of adding replicas?

Vertical Pod Autoscaler addresses a problem HPA cannot solve: inefficient resource allocation per pod. VPA observes actual CPU and memory consumption over time and recommends (or enforces) updated resource requests and limits. This is invaluable for workloads where horizontal scaling is ineffective or impossible.

VPA modes and safety constraints

VPA operates in three modes, and choosing wrong causes outages:

  1. Off (Recommendation Only): VPA analyzes usage and exposes recommended values via its status field. No automatic changes. This is the only safe starting point for existing production workloads.
  2. Initial: Sets resources only at pod creation time. Existing pods retain their original specs until restarted manually. Safe for gradual adoption.
  3. Auto: Recreates pods whenever recommendations deviate significantly from current requests. This guarantees optimal sizing but causes restarts. Never enable Auto on single-replica stateful services or databases without understanding the disruption.

In my experience maintaining legal-tech portals with variable document processing loads, VPA in recommendation mode revealed that our PDF generation containers were requesting 2Gi memory but consistently using only 400Mi, while occasionally spiking to 1.8Gi. The initial static requests were either wasteful or dangerously tight. VPA provided the data to set accurate baselines before we ever considered auto-mode.

The HPA-VPA conflict you must prevent

Critical rule: Never run VPA in Auto mode on the same metric dimension as HPA. If HPA scales on CPU utilization and VPA simultaneously adjusts CPU requests, they enter a destructive feedback loop. VPA increases requests → utilization drops → HPA scales down → fewer pods handle load → utilization spikes → HPA scales up → VPA sees high usage and increases requests again.

The supported pattern is: use VPA to right-size memory (which HPA rarely scales on reliably due to OOMKill risks), and use HPA to scale replicas based on CPU or custom metrics. Alternatively, use VPA in Off mode purely as a recommendation engine feeding manual tuning or GitOps pipelines. Teams building scalable product catalog systems often find this hybrid approach balances automation with predictability.

Scaling Need?What dimension needs adjustment?Replica Count→ Use HPAPod Resources→ Use VPANode Capacity→ Cluster AutoscalerStateless / ParallelRight-sizing / MemoryPending Pods / Cost
Decision framework for selecting the correct Kubernetes autoscaler based on whether you need to adjust replicas, pod resources, or cluster node capacity

How does Cluster Autoscaler interact with HPA and VPA in production?

Cluster Autoscaler (CA) operates at the infrastructure layer, completely independent of pod-level metrics. It watches for pods stuck in Pending state due to insufficient resources and provisions new nodes accordingly. Conversely, it identifies underutilized nodes and removes them after a configurable grace period. CA is what makes cloud-hosted Kubernetes economically viable for variable workloads.

The dependency chain matters

Understanding the causal chain prevents debugging nightmares:

  1. HPA decides to scale from 5 to 15 replicas based on queue depth.
  2. Scheduler attempts to place 10 new pods but finds no node with sufficient allocatable resources.
  3. Pods enter Pending state with Unschedulable condition.
  4. Cluster Autoscaler detects unschedulable pods matching its node group configuration.
  5. CA requests new nodes from the cloud provider API.
  6. Nodes join the cluster, pods schedule, HPA target is satisfied.

If any link breaks, your application fails silently. Common failure points include: CA misconfigured node group labels not matching pod node selectors, cloud provider quota exhaustion, or CA's --scale-down-delay-after-add being too long causing prolonged pending states during rapid scale-ups. On projects using regional cloud providers with limited instance availability, I always configure fallback node groups with different instance types to prevent single-SKU stockouts from blocking autoscaling entirely.

Cost implications of uncoordinated scaling

Without proper integration, CA can over-provision massively. If VPA in Auto mode suddenly doubles memory requests across all pods during a recommendation update, existing nodes become insufficient. CA adds nodes. Then VPA revises downward. Nodes are now underutilized but CA's scale-down delay keeps them running for 10+ minutes. Repeat this cycle hourly and your monthly bill inflates 30-40% without serving additional traffic.

Mitigation strategies include setting VPA update policies to Recreate only during maintenance windows, configuring CA's --scale-down-utilization-threshold conservatively (0.5-0.6 instead of default 0.5), and using priority classes to ensure critical workloads preempt batch jobs during resource contention rather than triggering unnecessary node additions.

FeatureHPAVPACluster Autoscaler
Scaling DimensionPod replica countPod CPU/memory requestsNode count per node group
Primary TriggerMetric threshold breachHistorical usage deviationUnschedulable pods / underutilized nodes
Safe With Others?Yes, if VPA avoids same metricOnly in Off/Initial mode with HPAYes, responds to HPA/VPA outcomes
Disruption RiskLow (new pods are additive)High in Auto mode (pod recreation)Medium (node drain + pod eviction)
Best ForStateless web/API workersRight-sizing, memory-bound appsCloud cost optimization, elastic capacity
2026 Stable APIautoscaling/v2autoscaling.k8s.io/v1Provider-specific (no k8s-native CRD)

What are the operational gotchas when combining all three autoscalers?

Theory suggests clean separation; reality delivers edge cases. After years of debugging production clusters, these patterns recur consistently:

Startup races and cold-start penalties

When HPA triggers scale-up and CA simultaneously provisions nodes, total time-to-ready includes: cloud VM boot (60-180s), kubelet registration (10-30s), image pull (variable), and application readiness probe passage. For Java or .NET applications with 30+ second startup times, end users experience degraded latency for 3-5 minutes during major scale events. Solutions include provisioned throughput node pools, pre-pulled images via DaemonSets, and HPA scaleUp.policies configured for burst capacity that assumes nodes already exist.

Memory-only workloads defeating HPA

Applications that consume memory proportionally to load but maintain constant CPU (e.g., caching layers, in-memory analytics) cannot use CPU-based HPA effectively. Memory-based HPA is dangerous because exceeding memory limits causes OOMKills rather than graceful degradation. The correct pattern is VPA in recommendation mode establishing accurate memory baselines, combined with custom-metric HPA scaling on business-relevant signals like cache hit ratio or active sessions. This requires investing in observability infrastructure upfront but prevents both under-scaling crashes and over-scaling waste.

TimeHPA TriggerPods PendingNode ProvisioningImage PullApp StartupReadyT+0sT+5sT+15sT+90sT+120sT+150sT+180sTotal Time-to-Ready: ~3 minutes (user-facing latency window)
End-to-end timeline from HPA trigger to pod ready state, highlighting the multi-minute gap where users experience degraded service during cold scale-ups

Testing autoscaling without production incidents

Never validate autoscaling behaviour exclusively in production. Use tools like k6 or Locust to generate synthetic load in staging clusters that mirror production node sizes and autoscaler configurations. Crucially, test scale-down paths as thoroughly as scale-up; many teams discover broken scale-down logic only after receiving unexpected bills. Implement monitoring alerts for persistent Pending pods (>2 minutes), VPA recommendation drift (>50% deviation), and CA failures to provision within SLA windows.

For teams operating in cost-sensitive environments, consider KEDA (Kubernetes Event-Driven Autoscaling) as a complement to native HPA. KEDA provides event-source-aware scaling (SQS, Kafka, Redis Streams) with built-in idle-to-zero capabilities that native HPA lacks. This eliminates baseline costs for truly sporadic workloads while retaining compatibility with Cluster Autoscaler's node management.

Implementing Kubernetes Autoscaling: HPA, VPA and Cluster Autoscaler Safely

Effective Kubernetes Autoscaling: HPA, VPA and Cluster Autoscaler implementation requires treating each component as a specialized tool rather than a universal solution. Start with HPA for stateless services using meaningful custom metrics, add VPA in recommendation-only mode to establish resource baselines, and deploy Cluster Autoscaler with conservative scale-down policies aligned to your cloud provider's billing granularity. Document your scaling policies alongside application code, review them quarterly against actual usage patterns, and resist the temptation to enable every autoscaling feature simultaneously. The goal is predictable performance at sustainable cost, not maximum automation for its own sake.

If your team needs hands-on guidance implementing these patterns for production workloads, or if you are evaluating whether Kubernetes autoscaling fits your current architecture, reach out to discuss your specific requirements. Proper autoscaling configuration pays for itself within weeks through avoided over-provisioning and prevented outages.

Frequently Asked Questions

HPA scales pod replicas based on metrics. VPA adjusts CPU and memory requests for existing pods. Cluster Autoscaler adds or removes nodes when pods cannot be scheduled or nodes are underutilized.

Use HPA for stateless workloads handling variable traffic. Use VPA for right-sizing resource requests or stateful applications where adding replicas is ineffective. Avoid using both simultaneously on the same metric to prevent scaling conflicts.

Costs depend entirely on cloud provider node pricing and usage patterns. Budget NPR 15,000–50,000 monthly (~USD 110–370) for small-to-medium clusters, but misconfigured autoscalers can triple bills overnight through unbounded scale-up events.

Technically yes, but only if they target different resources. Configure HPA for custom metrics like queue depth while VPA handles CPU and memory right-sizing. Using both on CPU causes oscillation as each controller fights to adjust the same resource dimension.

Verify metrics-server is running and returning data via kubectl top pods. Check that resource requests are defined on containers since HPA calculates utilization against requests not limits. Confirm the HPA target matches your actual metric name and namespace.

Set scale-down-delay-after-add to at least ten minutes and scale-down-unneeded-time to fifteen minutes minimum. Add pod disruption budgets to critical workloads. Use cluster-autoscaler.kubernetes.io/safe-to-evict=false annotation on pods that must not be interrupted during scale-down events.

Use Prometheus Adapter for custom business metrics like active WebSocket connections, queue length, or requests per second. For Nepal-based e-commerce platforms I have built, scaling on order-processing queue depth proved more reliable than CPU during Dashain traffic spikes.

VPA restarts pods when applying new resource recommendations unless update mode is set to Off or Initial. In production legal-tech portals I maintain, we use VPA in recommendation mode only, then apply changes manually during maintenance windows to avoid unexpected downtime.

Missing resource requests prevents HPA from calculating utilization. Setting minReplicas too low causes cold-start latency. Forgetting pod disruption budgets leads to simultaneous evictions. Not testing scale-down behavior results in orphaned nodes. Always validate with load testing before enabling in production.

Export HPA and VPA metrics to Prometheus and build dashboards showing current versus target replicas, recommendation history, and scale event timestamps. Alert on HPA stuck at maxReplicas or VPA recommendations diverging significantly from actual usage. Review Cluster Autoscaler logs daily for failed scale operations.

Yes, but requires careful configuration. Set Cluster Autoscaler expander strategy to priority or least-waste. Annotate node groups with appropriate taints and tolerations. Ensure critical workloads have anti-affinity rules to distribute across on-demand nodes. Expect interruptions and design applications for graceful shutdown handling.

Typically two to five minutes depending on cloud provider API response time and node boot sequence. AWS EKS averages three minutes. GKE with pre-provisioned node pools can achieve under sixty seconds. Factor this delay into capacity planning and set HPA thresholds conservatively to trigger scaling before saturation.

Yes, by right-sizing over-provisioned workloads. On one production Laravel application I optimized, VPA recommendations revealed containers requesting four times actual memory usage. Applying those recommendations reduced node count by thirty percent. However VPA alone does not scale down unused nodes; combine with Cluster Autoscaler for full savings.

Restrict RBAC permissions for metrics-server and autoscaler service accounts to minimum required resources. Validate webhook configurations for custom metrics adapters. Audit Cluster Autoscaler cloud-provider credentials regularly. Never grant cluster-admin to autoscaling components. Network policies should isolate metrics endpoints from external access.

Create a staging namespace with identical HPA VPA and Cluster Autoscaler configurations. Use k6 or Locust to generate synthetic load matching production patterns. Observe scaling events, measure response times during transitions, and verify scale-down completes cleanly. Only promote configurations after validating both scale-up and scale-down cycles multiple times.

Share this article

Quick Contact Options
Choose how you want to connect me: