KubernetesLXXXIII · Vertical Pod Autoscaling ConceptsVertical Pod Autoscaler
VPA admission controller — the mutating webhook
What you'll learn
- Explain how the VPA admission controller sets the requests
- Identify the mutating webhook configuration
- Diagnose admission controller failures
- Configure the admission controller for production
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The VPA admission controller is a mutating webhook that runs in the cluster. It intercepts the pod creation and sets the resource requests to the VPA-recommended values. This lesson walks the admission controller, the webhook configuration, and the failure modes.
The admission controller
The VPA admission controller is a mutating webhook:
flowchart LR
A[Pod creation] --> B[API server]
B --> C[Admission controller]
C --> D[Set resource requests]
D --> E[Mutated pod]
E --> F[Kubelet]
F --> G[Pod with VPA-recommended requests]
The mutation is transparent to the pod spec. The Deployment’s pod template is not modified; the mutation happens at pod creation time.
The webhook configuration
The mutation is configured via a MutatingWebhookConfiguration:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: vpa-webhook
webhooks:
- name: vpa.k8s.io
clientConfig:
service:
name: vpa-admission-controller
namespace: kube-system
path: /
port: 8000
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
namespaceSelector:
matchLabels:
vpa-enabled: "true"
failurePolicy: Ignore
sideEffects: None
admissionReviewVersions: ["v1"]
The webhook matches pods with the vpa-enabled: "true"
label.
The mutation
The pod creation:
# Pod spec (in Deployment)
spec:
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
cpu: 100m
memory: 128Mi
The mutated pod:
# Mutated pod (after VPA admission)
spec:
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
cpu: 150m # VPA-recommended
memory: 200Mi # VPA-recommended
The mutation changes the requests to the VPA-recommended values.
The verify
kubectl get pod nginx-1-abc -o jsonpath='{.spec.containers[0].resources.requests}'
{"cpu":"150m","memory":"200Mi"}
The output confirms the VPA-recommended requests are applied.
The interaction with the Pod spec
The VPA admission controller interacts with the Pod spec:
sequenceDiagram
participant D as Deployment
participant API as API server
participant VPA as VPA admission
participant K as Kubelet
D->>API: create pod
API->>VPA: mutate pod
VPA->>VPA: get recommended requests
VPA->>VPA: set resources.requests
VPA-->>API: mutated pod
API->>K: schedule pod
Note over K: Pod has VPA-recommended requests
The mutation happens between the API server and the kubelet.
The failurePolicy
The webhook’s failurePolicy determines the behavior on failure:
failurePolicy: Ignore
Ignore: if the webhook is unreachable, the pod is created without the VPA mutation.Fail: if the webhook is unreachable, the pod is rejected.
Ignore is the production default. The VPA mutation is
not critical; the pod can run without it.
The namespace selector
The webhook’s namespace selector limits the mutation to specific namespaces:
namespaceSelector:
matchLabels:
vpa-enabled: "true"
Only namespaces with the vpa-enabled: "true" label have
the VPA mutation applied.
kubectl label namespace default vpa-enabled=true
The label is applied to the namespace.
The admission controller deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: vpa-admission-controller
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: vpa-admission-controller
template:
metadata:
labels:
app: vpa-admission-controller
spec:
containers:
- name: admission-controller
image: registry.k8s.io/autoscaling/vpa-admission-controller:v0.13.x
ports:
- containerPort: 8000
The admission controller is a single replica. The webhook is HA by virtue of the API server’s retry behavior.
The failure modes
The common failure modes:
Admission controller unavailable
Error from server: failed calling webhook "vpa.k8s.io": connection refused
The admission controller is not running. Verify the pod status:
kubectl get pods -n kube-system -l app=vpa-admission-controller
Wrong namespace selector
Pod created without VPA mutation
The namespace selector is misconfigured. Verify the namespace labels.
Wrong container name
VPA recommendation does not apply to the container
The VPA targets a specific container. Verify the
containerPolicies configuration.
flowchart LR
A[Admission controller issue] --> B{Type?}
B -->|Unavailable| C[Check pod status]
B -->|Namespace selector| D[Check namespace labels]
B -->|Wrong container| E[Check containerPolicies]
Cross-course references
- The HPA course (Part LXXXII) covers the horizontal alternative.
- The Prometheus course covers VPA metrics.
- The Observability course covers VPA monitoring.
Quiz
Knowledge check · 4 questions
Q1. Where does the VPA admission controller mutate the pod spec?
Q2. failurePolicy: Fail on the VPA webhook can block pod creation if the admission controller is unavailable.
Q3. Walk the diagnosis of pods that are not being mutated by the VPA admission controller.
Deployment nginx with VPA. The pods are created with the original requests, not the VPA-recommended requests. The team is investigating.
Q4. What is the role of the namespace selector in the VPA admission controller?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Deploy the admission controller as a single replica. HA is via the API server’s retry.
- Use failurePolicy: Ignore. Avoid blocking pod creation.
- Set the namespace selector. Limit the VPA’s scope.
- Verify the namespace labels. The label must be present.
- Test the VPA on staging. Catch the mutation issues before production.
- Document the admission controller config. The selector, the failurePolicy, the namespace.
The VPA admission controller is the mutation engine. Operating it well is deploying the controller, setting the selector, and testing the mutation.