What Is Kubernetes VPA (Vertical Pod Autoscaler)? Explained Simply
Kubernetes VPA explained from scratch — what Vertical Pod Autoscaler does, how it differs from HPA, the three modes (Off, Initial, Auto), real-world use cases, and why most teams use it in Off mode for recommendations only.
If you have ever looked at your Kubernetes cluster and wondered "are my resource requests actually right?" — VPA is the answer to that question.
VPA (Vertical Pod Autoscaler) watches how much CPU and memory your pods actually use and recommends (or automatically sets) better resource requests and limits. It is not as widely used as HPA, but for teams trying to right-size their pods without guessing, it is genuinely useful.
The Problem VPA Solves
Setting resource requests in Kubernetes is mostly guesswork, especially for new applications. You either:
- Set too high: waste money on reserved but unused cluster resources
- Set too low: get OOMKilled errors or CPU throttling under load
VPA observes actual usage over time and tells you what the right values should be based on real data.
VPA vs HPA: Different Problems
These are frequently confused because both say "autoscaler." They solve different problems:
HPA (Horizontal Pod Autoscaler): Scales the number of pods based on CPU, memory, or custom metrics. Same pod spec, more replicas when load increases.
VPA (Vertical Pod Autoscaler): Adjusts the size of individual pods — changing resource requests/limits on existing pods. Does not change replica count.
They can work together: HPA handles traffic spikes by adding pods, VPA ensures each pod has the right resource allocation over time.
VPA Components
VPA has three components that are installed separately from the cluster:
VPA Recommender: Watches pod metrics, calculates recommended resource values, and writes them to VPA objects. Always running, continuously updating recommendations.
VPA Admission Controller (Webhook): Intercepts new pod creation and can adjust resource requests before the pod is scheduled — only applies when VPA mode is Initial or Auto.
VPA Updater: Evicts running pods so they restart with updated resource values — only active in Auto mode.
Installing VPA
VPA is not installed by default on any cluster. You install it from the official autoscaler repository:
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-install.shOr with Helm:
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install vpa fairwinds-stable/vpa --namespace kube-systemVerify:
kubectl get pods -n kube-system | grep vpa
# vpa-admission-controller-xxx Running
# vpa-recommender-xxx Running
# vpa-updater-xxx RunningVPA Modes
The updateMode field in a VPA object controls how aggressively VPA acts:
Mode: Off (Recommendation Only)
The most commonly used mode. VPA calculates and displays recommendations but makes no changes:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-api-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-api
updatePolicy:
updateMode: "Off" # Recommendations only — no automatic changes
resourcePolicy:
containerPolicies:
- containerName: api
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: "4"
memory: 4GiCheck recommendations:
kubectl describe vpa my-api-vpa -n production
# Output includes:
# Recommendation:
# Container Recommendations:
# Container Name: api
# Lower Bound:
# Cpu: 200m
# Memory: 256Mi
# Target:
# Cpu: 450m
# Memory: 512Mi
# Uncapped Target:
# Cpu: 450m
# Memory: 512Mi
# Upper Bound:
# Cpu: 2
# Memory: 1GiThe recommendation gives you three values:
- Lower bound: Minimum that should be set (risk of OOMKill below this)
- Target: VPA's recommended value based on observed usage
- Upper bound: Safety margin above target
Most teams use Off mode — they read the recommendations and manually update their Helm values or Terraform, instead of letting VPA auto-update in production.
Mode: Initial
VPA sets resource requests on new pods when they are created but never touches running pods. Safe and predictable:
updatePolicy:
updateMode: "Initial"Good for: new deployments where you want VPA to set reasonable initial values, but you control rollouts manually.
Mode: Auto
VPA automatically updates resource requests on running pods by evicting them and letting them restart with new values. Most powerful but also most disruptive:
updatePolicy:
updateMode: "Auto"VPA in Auto mode can evict your pods at any time to apply resource updates. This is problematic for:
- Applications with long startup times
- Services where any restart causes brief downtime
- Stateful applications (though you can target specific containers)
Known limitation: VPA and HPA cannot both manage CPU/memory on the same deployment. If HPA is managing based on CPU, VPA changing CPU requests will affect HPA's scaling decisions unexpectedly.
Practical Usage: Using VPA for Right-Sizing
The most common real-world workflow:
- Deploy VPA in
Offmode against your production workloads - Wait 7-14 days to collect realistic usage data
- Check recommendations:
kubectl describe vpa -n production - Update your manifests to match the VPA target values
- Roll out the changes through your normal deployment process
- Repeat quarterly or after major usage changes
# Quick script to see all VPA recommendations in a namespace
kubectl get vpa -n production -o json | \
jq '.items[] | {name: .metadata.name, recommendation: .status.recommendation}'What VPA Does Not Do
- Does not handle traffic spikes (use HPA for that)
- Does not work well with HPA on the same resource type simultaneously
- Does not guarantee no OOMKills — it can only recommend based on observed history; new usage patterns may still OOMKill
- Does not have a built-in way to apply recommendations automatically in a GitOps-friendly way (tools like Goldilocks help with this)
Goldilocks: VPA with a Dashboard
Goldilocks wraps VPA in Off mode with a web dashboard that shows recommendations in a friendly format:
helm install goldilocks fairwinds-stable/goldilocks --namespace goldilocks --create-namespace
# Enable for a namespace
kubectl label namespace production goldilocks.fairwinds.com/enabled=trueGoldilocks creates VPA objects in Off mode for all Deployments in labeled namespaces and provides a UI where you can see recommendations and copy the YAML changes directly.
More Kubernetes auto-scaling? Read our Kubernetes HPA complete guide and KEDA event-driven autoscaling guide.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
What Is OpenTelemetry? Observability Standard Explained Simply
OpenTelemetry (OTel) is the open standard for collecting traces, metrics, and logs. Learn what it is, why it matters, and how to start using it.
AI-Powered Kubernetes Anomaly Detection: Beyond Static Thresholds
Static alerts miss 40% of real incidents. Learn how AI and ML-based anomaly detection — using tools like Prometheus + ML, Dynatrace, and custom LLM runbooks — catches what thresholds can't.
Build an AI Kubernetes Event Analyzer with Claude API
Build a Python tool that collects kubectl events and pod status, sends them to Claude API for AI analysis, identifies root causes, and posts alerts to Slack — deployable as a Kubernetes CronJob.