Kubernetes HPA & VPA Auto-Scaling: Elastic Strategies for Traffic Spikes
An in‑depth comparison of Kubernetes Horizontal and Vertical Pod Autoscalers—including algorithms, configurations, performance benchmarks, mixed‑mode trade‑offs, custom‑metric integrations, and real‑world case studies—demonstrates how to choose and tune HPA, VPA, and KEDA for rapid traffic spikes while avoiding conflicts.
Overview
Comparison of Kubernetes Horizontal Pod Autoscaler (HPA) and Vertical Pod Autoscaler (VPA) from algorithm, deployment, performance and scenario perspectives. All examples run on Kubernetes 1.32+.
Scaling dimensions
Direction : HPA – horizontal (adds/removes Pods); VPA – vertical (adjusts Pod resources).
Target objects : HPA works on Deployment/StatefulSet/ReplicaSet; VPA works on Pod resources (requests/limits).
API version : HPA – autoscaling/v2 (stable); VPA – autoscaling.k8s.io/v1 (CRD required).
Response time : HPA evaluates metrics every 15 s (configurable) and can scale within seconds‑minutes; VPA needs minutes because it recreates Pods.
Typical workloads : HPA – stateless, request‑driven services; VPA – stateful or single‑instance services where long‑term profiling is needed.
Interaction with Cluster Autoscaler : HPA triggers node provisioning directly; VPA changes requests which may cause evictions that the Cluster Autoscaler handles indirectly.
Test environment
A simple Go HTTP service ( autoscale-test) exposing /compute, /memory and /healthz is deployed with 2 replicas, CPU request 200 m, limit 500 m, memory request 128 Mi, limit 256 Mi. Load is generated with k6 using a staged ramp‑up profile (warm‑up, steady, peak, cooldown).
HPA v2 algorithm
desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue)]The controller runs in kube‑controller‑manager and evaluates metrics every --horizontal-pod-autoscaler-sync-period (default 15 s). A tolerance window ( --horizontal-pod-autoscaler-tolerance, default 0.1) prevents oscillation; scale‑down uses a stabilization window (default 5 min).
HPA metric types (v2)
Resource – CPU/Memory utilization from Metrics Server.
Pods – per‑Pod custom metric (requires Prometheus Adapter or KEDA).
Object – custom metric on a Kubernetes object (also via Adapter/KEDA).
External – metric from outside the cluster (e.g., queue depth, via KEDA).
Sample HPA configuration (CPU 60 % target)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: autoscale-test
namespace: autoscale-lab
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: autoscale-test
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 60
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
selectPolicy: MinVPA component architecture
Recommender – analyses historical CPU/Memory usage and produces target, lower‑bound and upper‑bound recommendations (P95, P50, P99).
Updater – compares current requests with recommendations; if deviation exceeds a threshold it evicts the Pod so that the Admission Controller can inject the new resources.
Admission Controller – intercepts Pod creation and injects the recommended resources.requests and resources.limits.
VPA modes
Off – only calculates recommendations; never changes Pods.
Initial – injects recommendations only at Pod creation.
Recreate – evicts Pods with out‑of‑range requests and recreates them.
Auto – automatically selects the best strategy (currently equivalent to Recreate).
Sample VPA configuration (Off mode)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: autoscale-test-vpa
namespace: autoscale-lab
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: autoscale-test
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: app
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: "4"
memory: 4Gi
controlledResources:
- cpu
- memoryPerformance test results (summary)
Time to first new Pod (peak) : HPA 45 s, VPA N/A, HPA+VPA 45 s, KEDA 30 s.
Maximum replicas during peak : HPA 12, VPA 2, HPA+VPA 12, KEDA 10.
P99 latency (peak) : HPA 850 ms, VPA 2800 ms, HPA+VPA 780 ms, KEDA 650 ms.
Error rate (peak) : HPA 0.3 %, VPA 8.5 %, HPA+VPA 0.2 %, KEDA 0.1 %.
Stabilization time after load : HPA 8 min, VPA N/A, HPA+VPA 8 min, KEDA 6 min.
Key findings
VPA Auto cannot keep up with sudden traffic spikes because Pod recreation introduces latency; it is best used for long‑term resource profiling.
Combining HPA (real‑time scaling) with VPA in Off mode yields the most stable and efficient scaling.
KEDA, driven by business metrics such as RPS, reacts earlier than CPU‑based HPA and achieves the lowest latency.
KEDA configuration example (RPS‑based scaling)
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: autoscale-test-keda
namespace: autoscale-lab
spec:
scaleTargetRef:
name: autoscale-test
pollingInterval: 10
cooldownPeriod: 300
minReplicaCount: 2
maxReplicaCount: 50
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring:9090
query: sum(rate(http_requests_total{namespace="autoscale-lab",deployment="autoscale-test"}[2m]))
threshold: "200"
authenticationRef:
name: prometheus-auth
- type: cpu
metadata:
value: "70"
authenticationRef:
name: cpu-auth
advanced:
horizontalPodAutoscalerConfig:
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 200
periodSeconds: 15
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 5
periodSeconds: 60
selectPolicy: MinReal‑world case studies
E‑commerce flash sale (HPA with multiple metrics)
During a 618 promotion the product‑detail API saw P99 latency up to 5 s. The original HPA (CPU 70 % target, scale‑up limited to 2 Pods per minute) was too conservative. Increasing scaleUp.policies to a 300 % increase every 15 s and raising minReplicas to 5 eliminated the latency spikes.
GPU‑based inference service (VPA Off for profiling)
A single‑instance inference service was initially allocated 4 CPU / 16 Gi. Actual usage was 0.8 CPU / 6 Gi. VPA Off recommended ~1.1 CPU and 7 Gi. Updating the Deployment requests to the VPA target reduced cluster CPU consumption by ~30 % without downtime.
Message queue consumer (KEDA with SQS trigger)
An SQS consumer scaled on queue depth. With HPA (CPU 70 %) the queue grew to 50 000 messages because CPU remained low. Replacing HPA with a KEDA ScaledObject that watches aws_sqs_queue_messages_visible (threshold 100 messages → 1 replica) kept the queue empty and allowed scaling to zero when idle.
HPA + VPA conflict (pod thrashing)
Deploying HPA (CPU 70 %) together with VPA in Auto mode caused VPA to raise CPU requests, which lowered the utilization percentage and triggered HPA to scale down, creating a feedback loop. Switching VPA to Off mode (or limiting VPA to Memory only) resolved the thrashing.
Best‑practice matrix
Stateless Web API – use HPA (CPU + custom RPS metric) with aggressive scale‑up and conservative scale‑down.
Message consumer – use KEDA with a queue‑depth trigger; supports scale‑to‑zero.
Stateful single instance – use VPA Auto (or Off with manual adjustments) for resource optimization.
Mixed workloads – combine HPA for real‑time scaling with VPA Off for periodic recommendation updates.
Flash‑sale / scheduled traffic – use KEDA cron trigger together with HPA; pre‑increase minReplicas during the event window.
GPU inference – use VPA Off for profiling; adjust requests manually.
Batch workers – use HPA with an external metric (e.g., queue length) or KEDA to enable scale‑to‑zero.
Full microservice fleet – HPA + VPA Off + Cluster Autoscaler (three‑layer autoscaling chain).
HPA parameter tuning guide
Conservative profile (core transaction paths)
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 600
policies:
- type: Pods
value: 1
periodSeconds: 120Aggressive profile (flash sales)
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 300
periodSeconds: 15
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 900
policies:
- type: Percent
value: 5
periodSeconds: 120Balanced profile (daily operations)
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 4
periodSeconds: 30
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60Monitoring and alerts
Prometheus alert rules (excerpt):
# HPA reached maxReplicas
- alert: HPAMaxedOut
expr: kube_horizontalpodautoscaler_status_current_replicas == kube_horizontalpodautoscaler_spec_max_replicas
for: 10m
labels:
severity: warning
annotations:
summary: "HPA {{ $labels.horizontalpodautoscaler }} has reached max replicas"
description: "Namespace {{ $labels.namespace }} HPA {{ $labels.horizontalpodautoscaler }} has been at max replicas for >10m. Consider increasing maxReplicas or optimizing performance."
# HPA utilization >130 % of target
- alert: HPAHighUtilization
expr: kube_horizontalpodautoscaler_status_target_metric / kube_horizontalpodautoscaler_spec_target_metric > 1.3
for: 15m
labels:
severity: warning
annotations:
summary: "HPA {{ $labels.horizontalpodautoscaler }} utilization >130 % of target"
description: "Consider increasing resources or maxReplicas."
# VPA recommendation drift
- alert: VPARecommendationDrift
expr: (vpa_recommendation_target{resource="cpu"} / kube_pod_container_resource_requests{resource="cpu"} > 2) or (kube_pod_container_resource_requests{resource="cpu"} / vpa_recommendation_target{resource="cpu"} > 3)
for: 1h
labels:
severity: info
annotations:
summary: "Pod {{ $labels.pod }} CPU request deviates >2× from VPA recommendation"Conclusion
HPA is the primary mechanism for handling sudden traffic spikes on stateless services; proper behavior settings can achieve scaling within 30‑60 s.
VPA excels at long‑term resource profiling; use Off mode together with HPA for optimal efficiency without service interruption.
Business‑metric‑driven scaling (Prometheus Adapter or KEDA) provides more precise scaling for I/O‑bound or event‑driven workloads.
Never let HPA and VPA control the same resource dimension simultaneously – this creates feedback loops and pod thrashing.
Cluster Autoscaler is the downstream engine that provisions nodes for new Pods; expect 3‑8 min from HPA decision to a ready Pod in a cold cluster.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Raymond Ops
Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
