🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

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.

Shubham5 min read
Share:Tweet

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:

bash
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
 
./hack/vpa-install.sh

Or with Helm:

bash
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install vpa fairwinds-stable/vpa --namespace kube-system

Verify:

bash
kubectl get pods -n kube-system | grep vpa
# vpa-admission-controller-xxx    Running
# vpa-recommender-xxx              Running
# vpa-updater-xxx                  Running

VPA 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:

yaml
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: 4Gi

Check recommendations:

bash
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:  1Gi

The 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:

yaml
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:

yaml
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:

  1. Deploy VPA in Off mode against your production workloads
  2. Wait 7-14 days to collect realistic usage data
  3. Check recommendations: kubectl describe vpa -n production
  4. Update your manifests to match the VPA target values
  5. Roll out the changes through your normal deployment process
  6. Repeat quarterly or after major usage changes
bash
# 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:

bash
helm install goldilocks fairwinds-stable/goldilocks --namespace goldilocks --create-namespace
 
# Enable for a namespace
kubectl label namespace production goldilocks.fairwinds.com/enabled=true

Goldilocks 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

Browse fixes
Newsletter

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

Comments