# Vertical Pod Autoscaling

LLMS index: [llms.txt](/llms.txt)

---

<!-- overview -->

In Kubernetes, a _VerticalPodAutoscaler_ automatically updates a workload management <a class='glossary-tooltip' title='A Kubernetes entity, representing an endpoint on the Kubernetes API server.' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/reference/using-api/api-concepts/#standard-api-terminology' target='_blank' aria-label='resource'>resource</a> (such as
a <a class='glossary-tooltip' title='Manages a replicated application on your cluster.' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/concepts/workloads/controllers/deployment/' target='_blank' aria-label='Deployment'>Deployment</a> or
<a class='glossary-tooltip' title='A StatefulSet manages deployment and scaling of a set of Pods, with durable storage and persistent identifiers for each Pod.' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/concepts/workloads/controllers/statefulset/' target='_blank' aria-label='StatefulSet'>StatefulSet</a>), with the
aim of automatically adjusting infrastructure <a class='glossary-tooltip' title='A defined amount of infrastructure available for consumption (CPU, memory, etc).' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/reference/glossary/?all=true#term-infrastructure-resource' target='_blank' aria-label='resource'>resource</a>
[requests and limits](/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) to match actual usage.

Vertical scaling means that the response to increased resource demand is to assign more resources (for example: memory or CPU) 
to the <a class='glossary-tooltip' title='A Pod represents a set of running containers in your cluster.' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/concepts/workloads/pods/' target='_blank' aria-label='Pods'>Pods</a> that are already running for the workload.
This is also known as _rightsizing_, or sometimes _autopilot_.
This is different from horizontal scaling, which for Kubernetes would mean deploying more Pods to distribute the load.

If the resource usage decreases, and the Pod resource requests are above optimal levels, 
the VerticalPodAutoscaler instructs the workload resource (the Deployment, StatefulSet, or other similar resource) 
to adjust resource requests back down, preventing resource waste.

The VerticalPodAutoscaler is implemented as a Kubernetes API resource and a 
<a class='glossary-tooltip' title='A control loop that watches the shared state of the cluster through the apiserver and makes changes attempting to move the current state towards the desired state.' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/concepts/architecture/controller/' target='_blank' aria-label='controller'>controller</a>.
The resource determines the behavior of the controller. 
The vertical pod autoscaling controller, running within the Kubernetes data plane,
periodically adjusts the resource requests and limits of its target (for example, a Deployment)
based on analysis of historical resource utilization,
the amount of resources available in the cluster, and real-time events such as out-of-memory (OOM) conditions.

<!-- body -->

## API object

The VerticalPodAutoscaler is defined as a <a class='glossary-tooltip' title='Custom code that defines a resource to add to your Kubernetes API server without building a complete custom server.' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/' target='_blank' aria-label='Custom Resource Definition'>Custom Resource Definition</a> (CRD) in Kubernetes. Unlike HorizontalPodAutoscaler, which is part of the core Kubernetes API, VPA must be installed separately in your cluster.

The current stable API version is `autoscaling.k8s.io/v1`. More details about the VPA installation and API can be found in the [VPA GitHub repository](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler).

## How does a VerticalPodAutoscaler work?



<figure class="diagram-large ">
    <img src="/images/docs/concepts/vpa-architecture.svg"
         alt="Vertical Pod Autoscaling architecture"/> <figcaption>
            <p>Figure 1. VerticalPodAutoscaler controls the resource requests and limits of Pods in a Deployment</p>
        </figcaption>
</figure>

<!-- https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqlVG1P2zAQ_iuW-RpY0rVNG6RJpSkSH9hQuzFpLZo850o9nDiznQKj_PddYqcvMGmaSKXG53vuuefuHD9RrjKgCb3VrFyRs8-LguBjqh9uY1SWUnBmhSrIV6XvpGKZg9QPV4XVSkrQ8xRKqR5zKCx5R6Zj_JtZZmFZyRnYm11IqbL5lcrQP8ZgJgrQ3guFZ3b_OVgtuJlfujeZgV5vsawU89HVxYvNLBfGoNL59dWIjFqrSeRU3uwnWJfsO9fza9AWK5QoalRZZXAJmoynqQdr4CrHujIssubdsz2iKjOs1Hn9Gj0HVZDj4w_7ka-oa8BmZpUGQ6btdtN2s_FKW0pnNQHjFfA7Q5ZKE75ixS0g2Cs4kNaAJ2vBrSF18xH_pfEYIgpSSsZhszdMF7uzm_Ap_KrAIEEB9zXJph5CqwmXDeij85Gxhkb8ZjeUFzPynNgdWKMMWYuxu4746Lby16EXxU_gXg02TVWaA1kzWdU9-IuyRhEYp_wfpbZV3Au7Ip9KK3ImcSouCdLjGW7puWTGpLCslZKlkDI5Gp6Pe5NBYJDxDpKjaIK_1JvH9yKzqyQqHwKupNKt-_QFG9eZZ0t7o_5Z-ja29hA6xvPzdNjvv42RlaVnO-un8ej_q93j2_8MAn9gg92wsbH72dvjjx062G5r9O8D3268AY6uFn9KA7zxREYTqysIaA46Z7VJn-rABbUryGFBE1xmsGSVtAu6KJ4xrGTFN6XyNlKr6nZFkyWTBi0nPxUMb88txG1OMoGf9xbJ8K6ZPRZ8y9PUP1ZVYWkSdZs8NHmiDzSJOyedXhiGUe_9IIw63SigjzQZhCfhMO5FcTwcdgaDuPsc0N-NsPBkENf4MBr0O_1uNx4GFJrsl-6ub6785z9_1f9X -->

Kubernetes implements vertical pod autoscaling through multiple cooperating components that run intermittently (it is not a continuous process). The VPA consists of three main components: 

* The _recommender_, which analyzes resource usage and provides recommendations.
* The _updater_, that Pod resource requests either by evicting Pods or modifying them in place.
* And the VPA _admission controller_ webhook, which applies resource recommendations to new or recreated Pods.

Once during each period, the Recommender queries the resource utilization for Pods targeted by each VerticalPodAutoscaler definition. The Recommender finds the target resource defined by the `targetRef`, then selects the pods based on the target resource's `.spec.selector` labels, and obtains the metrics from the resource metrics API to analyze actual CPU and memory consumption.

The Recommender analyzes both current and historical resource usage data (CPU and memory) for each Pod targeted by the VerticalPodAutoscaler. It examines:
- Historical consumption patterns over time to identify trends
- Peak usage and variance to ensure sufficient headroom
- Out-of-memory (OOM) events and other resource-related incidents

Based on this analysis, the Recommender calculates three types of recommendations:
- Target recommendation (optimal resources for typical usage)
- Lower bound (minimum viable resources)
- Upper bound (maximum reasonable resources).

These recommendations are stored in the VerticalPodAutoscaler resource's `.status.recommendation` field.


The _updater_ component monitors the VerticalPodAutoscaler resources and compares current Pod resource requests with the recommendations. When the difference exceeds configured thresholds and the update policy allows it, the updater can either:

- Evict Pods, triggering their recreation with new resource requests (traditional approach)
- Update Pod resources in place without eviction, when the cluster supports in-place Pod resource updates

The chosen method depends on the configured update mode, cluster capabilities, and the type of resource change needed. In-place updates, when available, avoid Pod disruption but may have limitations on which resources can be modified. The updater respects PodDisruptionBudgets to minimize service impact.

The _admission controller_ operates as a mutating webhook that intercepts Pod creation requests. It
checks if the Pod is targeted by a VerticalPodAutoscaler and, if so, applies the recommended
resource requests and limits before the Pod is created. More specifically, the admission controller uses the Target recommendation in the VerticalPodAutoscaler resource's `.status.recommendation` stanza as the new resource requests. The admission controller ensures new Pods start with appropriately sized resource allocations, whether they're created during initial deployment, after an eviction by the updater, or due to scaling operations.

The VerticalPodAutoscaler requires a metrics source, such as Kubernetes' Metrics Server <a class='glossary-tooltip' title='Resources that extend the functionality of Kubernetes.' data-bs-toggle='tooltip' data-bs-placement='top' href='/docs/concepts/cluster-administration/addons/' target='_blank' aria-label='add-on'>add-on</a>,
to be installed in the cluster.
The VPA components fetch metrics from the `metrics.k8s.io` API. The Metrics Server needs to be launched separately as it is not deployed by default in most clusters. For more information about resource metrics, see [Metrics Server](/docs/tasks/debug/debug-cluster/resource-metrics-pipeline/#metrics-server).

## Update modes

A VerticalPodAutoscaler supports different _update modes_ that control how and when
resource recommendations are applied to your Pods. You configure the update mode using
the `updateMode` field in the VPA spec under `updatePolicy`:

```yaml
---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Recreate"  # Off, Initial, Recreate, InPlaceOrRecreate, InPlace
```

### Off {#updateMode-Off}

In the _Off_ update mode, the VPA recommender still analyzes resource usage and generates
recommendations, but these recommendations are not automatically applied to Pods.
The recommendations are only stored in the VPA object's `.status` field.

You can use a tool such as `kubectl` to view the `.status` and the recommendations in it.

### Initial {#updateMode-Initial}

In _Initial_ mode, VPA only sets resource requests when Pods are first created. It does not update resources for already running Pods, even if recommendations change over time. The recommendations apply only during Pod creation.

### Recreate {#updateMode-Recreate}

In _Recreate_ mode, VPA actively manages Pod resources by evicting Pods when their current
resource requests differ significantly from recommendations. When a Pod is evicted, the workload
controller (managing a Deployment, StatefulSet, etc) creates a replacement Pod, and the VPA admission
controller applies the updated resource requests to the new Pod.

### InPlaceOrRecreate {#updateMode-InPlaceOrRecreate}

In `InPlaceOrRecreate` mode, VPA attempts to update Pod resource requests and limits without restarting the Pod when possible. However, if in-place updates cannot be performed for a particular resource change, VPA falls back to evicting the Pod
(similar to `Recreate` mode) and allowing the workload controller to create a replacement Pod with updated resources.

In this mode, the updater applies recommendations in-place using the [Resize Container Resources In-Place](/docs/tasks/configure-pod-container/resize-container-resources/) feature.


### InPlace {#updateMode-InPlace}

This mode is available as an alpha feature in VPA 1.7.0 and requires
Kubernetes 1.33 or later with the `InPlacePodVerticalScaling` cluster feature
gate enabled, and the `InPlace` feature gate enabled on the VPA updater and
admission controller. It uses the
[in-place Pod resize](/docs/concepts/workloads/pods/pod-lifecycle/#pod-resize)
feature to apply updates without disrupting the Pod.

In `InPlace` mode, VPA attempts to update Pod resource requests and limits without
restarting or evicting the Pod. Unlike `InPlaceOrRecreate`, this mode **never falls
back to eviction**. If an in-place update cannot be applied (for example, because the
node does not have enough capacity), VPA defers the update and retries it in a
subsequent reconciliation loop.

To use `InPlace` mode, enable the `InPlace` feature gate on both the VPA updater
and admission controller:

```shell
--feature-gates=InPlace=true
```

Then set `updateMode` to `"InPlace"` in your VPA spec:

```yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "InPlace"
```

**Key difference from `InPlaceOrRecreate`:** When a resize is deferred, in progress,
or infeasible, `InPlace` mode always waits and retries — it never evicts the Pod,
regardless of how long the update is pending.

### Auto (deprecated) {#updateMode-Auto}


<div class="alert alert-info" role="note"><h4 class="alert-heading">Note:</h4>The <code>Auto</code> update mode is <strong>deprecated since VPA version 1.4.0</strong>. Use <code>Recreate</code> for
eviction-based updates, or <code>InPlaceOrRecreate</code> for in-place updates with eviction fallback.</div>


`Auto` mode is currently an alias for `Recreate` mode and behaves identically. It was introduced to allow for future expansion of automatic update strategies.

## Resource policies

Resource policies allow you to fine-tune how the VerticalPodAutoscaler generates recommendations and applies updates.
You can set boundaries for resource recommendations, specify which resources to manage, and configure different policies for individual containers within a Pod.

You define resource policies in the `resourcePolicy` field of the VPA spec:

```yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Recreate"
  resourcePolicy:
    containerPolicies:
    - containerName: "application"
      minAllowed:
        cpu: 100m
        memory: 128Mi
      maxAllowed:
        cpu: 2
        memory: 2Gi
      controlledResources:
      - cpu
      - memory
      controlledValues: RequestsAndLimits
```

#### minAllowed and maxAllowed

These fields set boundaries for VPA recommendations.
The VPA will never recommend resources below `minAllowed` or above `maxAllowed`, even if the actual usage data suggests different values.

#### controlledResources

The `controlledResources` field specifies which resource types VPA should manage for a container in a Pod.
If not specified, VPA manages both CPU and memory by default. You can restrict VPA to manage only specific resources.
Valid resource names include `cpu` and `memory`.

### controlledValues

The `controlledValues` field determines whether VPA controls resource requests, limits, or both:

RequestsAndLimits
: VPA sets both requests and limits. The limit scales proportionally to the request based on the request-to-limit ratio defined in the Pod spec. This is the default mode.

RequestsOnly
: VPA only sets requests, leaving limits unchanged. Limits are respected and can still trigger throttling or out-of-memory kills if usage exceeds them.

See [requests and limits](/docs/concepts/configuration/manage-resources-containers/#requests-and-limits) to learn more about those two concepts.

## LimitRange resources

The admission controller and updater VPA components post-process recommendations to comply with the constraints defined in [LimitRanges](/docs/concepts/policy/limit-range/). The LimitRange resources with `type` Pod and Container are checked in the Kubernetes cluster. 

For example, if the `max` field in a Container LimitRange resource is exceeded, both VPA components lower the limit to the value defined in the `max` field, and the request is proportionally decreased to maintain the request-to-limit ratio in the Pod spec.

## What's next

If you configure autoscaling in your cluster, you may also want to consider using
[node autoscaling](/docs/concepts/cluster-administration/node-autoscaling/)
to ensure you are running the right number of nodes.
You can also read more about [_horizontal_ Pod autoscaling](/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/).
