Choosing Between HPA, VPA, and Cluster Autoscaler in Kubernetes
Guide to choosing and configuring HPA, VPA, and Cluster Autoscaler in Kubernetes based on workload metrics, pod resizing safety, and node‑group elasticity.
24 Aug 2025, 15:25 UTC

Decision and constraints
You need to autoscale a Kubernetes workload while balancing performance, cost, and stability. The choice depends on three constraints:
- Metric availability – Horizontal Pod Autoscaler (HPA) and Vertical Pod Autoscaler (VPA) require the metrics‑server or a custom metrics adapter to expose CPU, memory, or application‑specific values.
- Pod resizing safety – VPA can change pod resource requests/limits; if not run in "Off" or "Initial" mode, it may trigger pod restarts.
- Node‑group elasticity – Cluster Autoscaler can only add or remove nodes when the underlying infrastructure (e.g., AWS ASG, GCP node pools) supports scaling and when node groups are correctly labeled/tainted.
If any constraint is not met, the corresponding autoscaler cannot be used reliably.
Comparison of options
| Option | Scales | Metric source | Restart impact | Setup complexity |
|---|---|---|---|---|
| Horizontal Pod Autoscaler (HPA) | Pod replicas | CPU/Memory/custom (via metrics‑server) | None (uses rolling update) | Low |
| Vertical Pod Autoscaler (VPA) | Pod resource requests/limits | Usage metrics (metrics‑server) | May cause restart unless update mode is "Off" or "Initial" | Medium |
| Cluster Autoscaler | Node count | Node utilization or pods pending scheduling | None (adds/removes nodes) | Medium‑High |
Trade‑offs
- HPA reacts quickly to load spikes because it changes replica count, but it cannot fix a pod that is chronically under‑provisioned; if the container requests are too low, adding replicas may not relieve pressure.
- VPA optimizes the resource footprint of each pod by aligning requests with actual usage, which can improve bin‑packing and reduce wasted nodes. However, when VPA is set to "Auto" mode it may evict and recreate pods, causing brief disruption.
- Cluster Autoscaler addresses capacity shortages at the node level (e.g., when many pods are pending). It adds latency because new nodes must be provisioned by the cloud provider, and it requires a compatible node‑group configuration and proper cloud‑provider credentials.
In practice, many teams run HPA for fast reaction, VPA in "Off" mode to obtain recommendations, and Cluster Autoscaler to ensure the cluster has enough nodes for those recommendations.
Concrete implementation and validation
The following example shows how to enable all three mechanisms on a simple web‑service Deployment, verify that the metrics‑server is healthy, and check each autoscaler’s behavior.
Prerequisites
- You have
kubectlconfigured with a user that canget,list, andcreateobjects in the target namespace (typicallydefaultor a dedicated app namespace). - The metrics‑server is deployed; if not, install it per your distribution’s docs.
- For Cluster Autoscaler, you need an AWS Auto Scaling Group (ASG) with appropriate IAM role and tags (e.g.,
k8s.io/cluster-autoscaler/enabledandk8s.io/cluster-autoscaler/). Replace placeholders with your cluster name and ASG name.
1. Deploy a sample application
# Save as web-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: "200m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
name: web-app-svc
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 80
type: ClusterIP
Apply the manifest:
kubectl apply -f web-app.yaml
2. Enable Horizontal Pod Autoscaler
Target 50% average CPU utilization across the pod set.
kubectl autoscale deployment web-app \
--cpu-percent=50 \
--min=2 \
--max=10
Required permission: autoscaling/v1 horizontalpodautoscalers create.
3. Enable Vertical Pod Autoscaler in “Off” mode (recommendations only)
# Save as vpa-web-app.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-app-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: web-app
updatePolicy:
updateMode: "Off" # does not restart pods
resourcePolicy:
containerPolicies:
- containerName: *
minAllowed:
cpu: "50m"
memory: "64Mi"
maxAllowed:
cpu: "1000m"
memory: "512Mi"
Apply:
kubectl apply -f vpa-web-app.yaml
Required permission: autoscaling.k8s.io/v1 verticalpodautoscalers create.
4. Configure Cluster Autoscaler (AWS example)
Ensure the ASG has the tags:
k8s.io/cluster-autoscaler/enabled=truek8s.io/cluster-autoscaler/=owned
Deploy the Cluster Autoscaler manifest (provided by AWS) with appropriate IAM role and --nodes flags:
# Example snippet; replace placeholders
containers:
- name: cluster-autoscaler
image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.28.0
args:
- --nodes=2:10:my-asg-name # format: min:max:ASGName
- --cloud-provider=aws
- --skip-nodes-with-system-pods=false
env:
- name: AWS_REGION
value: "us-east-1"
Apply the full manifest per the provider’s guide. Required permission: ability to describe and update the ASG, and get/list on nodes and pods.
5. Validation steps
- Metrics‑server health:
Expect thekubectl get deployment metrics-server -n kube-system kubectl top nodesmetrics-serverpod to beRunningandkubectl top nodesto return CPU/memory numbers. - HPA validation:
Look forkubectl get hpa web-app # Generate load (example using hey, run from a pod with network access) hey -z 2m -c 10 http://web-app-svc # After load, re‑check HPA kubectl get hpa web-appTARGETSmoving toward the 50% goal andREPLICASincreasing. - VPA recommendation validation:
Inspect thekubectl get vpa web-app-vpa -o yamlstatus.recommendationblock for suggested CPU/memory values. - Cluster Autoscaler validation:
The pod should go# Schedule a pod that requests more resources than available kubectl run pause --image=nginx --restart=Never --requests=cpu=2,memory=4Gi # Check pending status kubectl get pods pause # After a minute, check node count kubectl get nodes # Or view ASG size in AWS consolePending, triggering the autoscaler to add a node; once the node joins, the pod should schedule.
Limitations and practical checks
- HPA relies on timely metrics; if the metrics‑server laggs, scaling decisions may be based on stale data.
- VPA in “Off” mode only gives advice; you must manually apply the recommended requests/limits or switch to a safer update mode after testing.
- Cluster Autoscaler adds node‑provision latency (typically 1‑2 minutes on public clouds) and cannot shrink below the ASG’s
minSizeor remove nodes with non‑daemonset pods that lack proper pod disruption budgets. - Running VPA and HPA on the same metric (e.g., both targeting CPU) can cause contention; keep them on different metrics or use VPA only for recommendation.
To confirm the overall setup works, repeat the load test after applying VPA recommendations (by updating the Deployment’s resource requests) and observe whether the cluster scales nodes via Cluster Autoscaler before HPA adds more replicas.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.