Configure VerticalPodAutoscaler
Learn to configure VerticalPodAutoscaler in Kubernetes for automatic resource management — hands-on steps, options, and troubleshooting.
Focus: configure verticalpodautoscaler for resources
You're running a dozen microservices and constantly guessing CPU and memory requests — over-provisioning to stay safe, yet still hitting OOMKilled errors or throttled containers. Manually tuning every Deployment's resource envelopes is tedious, error-prone, and never quite right. The VerticalPodAutoscaler (VPA) automates this: it observes your pod usage, calculates the optimal request and limit, and adjusts without you touching YAML by hand.
The problem this lesson solves
Kubernetes relies on requests and limits to schedule pods and enforce resource boundaries. When these values are off, you pay the price:
- Under-requesting → pods get scheduled on overcommitted nodes, leading to CPU throttling or, worse, the kubelet kills them with OOMKilled.
- Over-requesting → nodes waste capacity, your cluster costs skyrocket, and you can't pack as many workloads.
- Static tuning doesn't work at scale — traffic patterns shift, code changes, and seasonal spikes invalidate yesterday's perfect numbers.
Manually editing a Deployment every week is not sustainable. VPA acts as a resource recommendation engine that runs in your cluster, learns from live usage, and either suggests or applies corrections automatically.
Core concept / mental model
Think of VPA as a thermostat for pod resources. Just as a thermostat measures room temperature and adjusts the HVAC to reach your target, VPA measures pod resource consumption and adjusts CPU/memory requests (and optionally limits) to match actual demand.
VPA components
A VPA deployment consists of three components that form a feedback loop:
| Component | Role |
|---|---|
| Recommender | Reads historical and real-time usage metrics from the Metrics Server, then computes recommended requests/limits for each container. |
| Updater | Evicts pods whose actual resource usage diverges significantly from the recommendation (only when mode allows eviction). |
| Admission Controller | Intercepts pod creation and mutates the pod spec to set the recommended resources. |
VPA modes
VPA operates in three distinct modes that control how much automation you want:
- Off – VPA only computes recommendations (stored in a ConfigMap / status). You must manually adjust the Deployment. Safe for production when you want advice but no automated changes.
- Auto – VPA both recommends and applies resources. The Updater evicts running pods when recommendations change, and new pods get the updated values via the admission webhook. Experimental; use with caution – eviction can cause disruption.
- Recreate – Similar to
Auto, but the Updater always recreates pods (by evicting them). No in-place updates. Suitable for workloads that tolerate brief restarts (e.g., batch jobs).
Pro tip: Start with
mode: Offto inspect the recommendations before switching toAutoin a staging environment.
How it works step by step
When you create a VPA object targeting a Deployment or StatefulSet, here is the lifecycle:
- Observation phase: The Recommender queries the Metrics Server every minute (configurable) to collect CPU and memory usage percentiles for each container in the target pods.
- Recommendation phase: Using a sliding window of up to 8 days of data, the Recommender calculates the target, lowerBound, and upperBound for each resource. The target is the recommended value; the bounds define safe limits.
- Update (if mode allows): If the current pod's resources differ from the target by more than a threshold (default 0.1% for CPU, 1% for memory — effectively immediate drift triggers), the Updater evicts the pod.
- Admission: When a new pod is created (either from a scale-up, rollout, or eviction), the VPA Admission Controller mutates the pod spec to set the container's requests (and optionally limits) to the recommended values.
Request vs limit behavior
VPA only sets requests by default. If you want it to also set limits, you must configure containerResourcePolicy per container. This is intentional — setting limits differently can cause thrashing and unexpected OOM kills.
What VPA does NOT do
- It does not set limits automatically (unless you explicitly opt in).
- It does not scale pods horizontally (use HPA for that — but VPA and HPA can coexist with care).
- It does not update the original Deployment/StatefulSet spec — it mutates pods only. To make changes persistent, you must copy the recommendation back to your Deployment YAML.
Hands-on walkthrough
Let's configure a VPA for a sample Deployment called web-server. You'll need a running Kubernetes cluster with Metrics Server installed and the VPA components deployed (we'll use the VPA manifests from the vertical-pod-autoscaler repo).
Prerequisites
# Install Metrics Server (if not present)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# Clone VPA repo and deploy components
cd /tmp
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh
Step 1: Create a sample Deployment
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
replicas: 1
selector:
matchLabels:
app: web-server
template:
metadata:
labels:
app: web-server
spec:
containers:
- name: nginx
image: nginx:latest
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 100m
memory: 200Mi
Apply it:
kubectl apply -f deployment.yaml
Step 2: Create a VPA object in Off mode
# vpa-off.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-server-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web-server
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: nginx
minAllowed:
cpu: 10m
memory: 50Mi
maxAllowed:
cpu: 1000m
memory: 1Gi
Apply the VPA:
kubectl apply -f vpa-off.yaml
Wait 1–2 minutes for the Recommender to collect metrics, then check the recommendations:
kubectl describe vpa web-server-vpa
You'll see output like:
Status:
Conditions:
Last Transition Time: 2025-03-01T10:00:00Z
Status: True
Type: RecommendationReady
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound:
Cpu: 5m
Memory: 65536k
Target:
Cpu: 15m
Memory: 128Mi
Upper Bound:
Cpu: 30m
Memory: 256Mi
The Target values are what VPA suggests. Your current Deployment uses 50m CPU and 100Mi memory requests — VPA says you can lower CPU to 15m and raise memory to 128Mi. Cool, right?
Step 3: Apply recommendation manually (Off mode)
Edit the Deployment and set requests to the target values from the VPA status:
kubectl edit deployment web-server
Change resources.requests.cpu to 15m and resources.requests.memory to 128Mi. Save and exit.
Step 4: Switch to Auto mode (staging only)
# vpa-auto.yaml (same as above but updateMode: "Auto")
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-server-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web-server
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: nginx
minAllowed:
cpu: 10m
memory: 50Mi
maxAllowed:
cpu: 1000m
memory: 1Gi
kubectl apply -f vpa-auto.yaml
# Pod will be evicted and recreated with new resources
kubectl get pods -w
Notice the old pod disappears and a new one appears with adjusted resources. Verify:
kubectl describe pod <new-pod-name> | grep -A5 Requests
Compare options / when to choose what
| Mode | Use case | Risk |
|---|---|---|
| Off | Production — get recommendations without disruption. You manually apply changes during maintenance windows. | None (read-only). |
| Auto | Staging / low-criticality services — automate resource tuning but accept pod evictions. | Can cause churn if usage spikes; pods restart frequently. |
| Recreate | Batch jobs or stateless workloads that tolerate restarts — same as Auto but always recreates. | Same as Auto, but pods are always replaced, not mutated in-place (which doesn't exist yet anyway). |
When to choose which: * For exploratory analysis →
Off* For automated tuning with acceptable disruption →Autoon non-production * For jobs or canary deployments →Recreate
VPA + HPA: can they co-exist?
Yes, but only if HPA scales based on custom/external metrics (not CPU/memory), because VPA adjusts resource requests while HPA adjusts replicas. If both target CPU, they fight — VPA changes the request, which changes the HPA's utilization calculation, causing oscillation. Rule of thumb: use HPA on CPU/memory only without VPA, or use VPA with HPA on custom metrics.
Troubleshooting & edge cases
VPA recommendations not appearing
Conditions:
Type: RecommendationReady
Status: False
Reason: MissingResourceRecommendation
- Cause: Metrics Server not reporting data, or target pod has no containers with resources.
- Fix: Ensure Metrics Server is running (
kubectl top podsworks). Verify the target Deployment has resources defined in its container spec. Wait 1–2 minutes after pod creation.
Pod stuck in Pending after VPA Auto update
- Cause: VPA set a request larger than available node capacity.
- Fix: Set
maxAllowedin the VPA spec to cap requests. Usekubectl describe podto checkEvents: FailedScheduling. AdjustmaxAllowedor add more nodes.
VPA recomputes too often, causing constant evictions
- Cause: Default
minReplicaspolicy is not set; VPA evicts even singleton pods, causing downtime. - Fix: For critical workloads, use
updateMode: Offor implement aPodDisruptionBudget(PDB) to limit concurrent evictions.
OOMKilled even with VPA
- Cause: VPA only sets requests, not limits. Limits may still be too low.
- Fix: Enable limit recommendation in
containerPolicy:
containerPolicies:
- containerName: nginx
controlledResources: ["cpu", "memory"]
controlledValues: RequestsAndLimits
VPA and DaemonSets or Jobs
VPA does not support DaemonSet (because pods cannot be evicted independently) and generally should not be used with Jobs that run once. Focus on Deployments and StatefulSets.
What you learned & what's next
You now know how to configure VerticalPodAutoscaler for resources — you understand the three modes (Off, Auto, Recreate), how to read recommendations, and how to apply them manually or automatically. You also learned the pitfalls: co-existing with HPA, setting safe bounds, and avoiding pod churn.
Next: Move to [[Configure PodDisruptionBudget for availability]] — learn how to protect your VPA-managed workloads from excessive evictions during voluntary disruptions.
Practice recap
Create a Deployment with a simple app (e.g., nginx) and deploy a VPA in Off mode. After 2 minutes, retrieve the recommendation with kubectl describe vpa. Manually apply the target CPU and memory requests to your Deployment. Then delete your VPA and test switching to updateMode: Auto in a non-production namespace, observing the pod eviction and recreation.
Common mistakes
- Leaving VPA in Auto mode on production before studying recommendations. Always start in Off mode and verify the target values won't cause scheduling failures.
- Forgetting to set maxAllowed and minAllowed. Without bounds, VPA can recommend zero (causing pod stuck) or a huge value that no node can fit.
- Running VPA and HPA both targeting CPU/memory on the same workload. They fight — VPA changes the request, HPA changes replicas, causing oscillation. Use HPA on custom metrics or use only one.
- Believing VPA updates the Deployment/StatefulSet YAML. VPA does not mutate the original resource spec; you must copy recommendations back if you want them to survive rollbacks or re-deploys.
Variations
- Goldilocks by Fairwinds – A dashboard tool that wraps VPA and provides an intuitive UI to inspect recommendations. Great for teams new to VPA.
- Kubernetes Events-driven scaling – Combine VPA with custom resource metrics via Prometheus Adapter for more granular decisions than the default Metrics Server.
- VPA with multiple containers – You can set per-container policies using
containerNameincontainerPolicies. Useful for sidecar-heavy pods (e.g., envoy + app).
Real-world use cases
- A SaaS company runs stateless web servers with unpredictable traffic; VPA in Off mode suggests weekly resource adjustments that cut cloud costs by 23%.
- A CI/CD platform uses VPA in Auto mode for build agents — each build may require different resources, and VPA optimizes per-pod, reducing idle node waste.
- A financial services firm uses VPA with minAllowed and maxAllowed on their StatefulSet (database caches) to prevent OOM during traffic spikes while avoiding manual tunings.
Key takeaways
- VPA automatically recommends or applies optimal CPU/memory requests by analyzing pod usage metrics over time.
- The three modes — Off (recommend only), Auto (evict + apply), and Recreate (always recreate) — let you control automation level.
- Always start with mode: Off in production to inspect recommendations before enabling Auto in staging.
- Set minAllowed and maxAllowed to prevent VPA from recommending extreme values that break scheduling.
- Do not use VPA and HPA together on CPU/memory; use VPA with HPA on custom metrics for a non-conflicting setup.
- VPA does not update the source Deployment YAML; persist recommendations as part of your CI/CD pipeline.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.