vertical-pod-autoscaler/benchmark/README.md
Measures VPA component latencies using KWOK (Kubernetes WithOut Kubelet) to simulate pods without real resource consumption.
<!-- toc -->Note: Currently only updater metrics are collected. Recommender metrics are planned for the future.
The full-benchmark.sh script handles everything end-to-end: creates a Kind cluster, deploys VPA, installs KWOK, configures VPA for benchmarking, builds and runs the benchmark.
cd vertical-pod-autoscaler
./benchmark/hack/full-benchmark.sh --profile=small --output=results.csv
You can pass any benchmark flags directly:
./benchmark/hack/full-benchmark.sh --profile=small,medium,large --runs=3 --output=results.csv
If you prefer to run each step individually (or if the cluster already exists):
# 1. Create a Kind cluster (the full-benchmark.sh script appends benchmark-specific
# kubeadmConfigPatches to .github/kind-config.yaml automatically; for manual setup,
# create a cluster with the base config or your own)
kind create cluster --config=.github/kind-config.yaml
# 2. Deploy VPA for benchmark
EXTRA_HELM_VALUES=./benchmark/hack/values.yaml ./hack/deploy-for-e2e-locally.sh full-vpa
# 3. Install KWOK and create fake node
./benchmark/hack/install-kwok.sh
# 4. Build and run
go build -C benchmark -o ../bin/vpa-benchmark .
./bin/vpa-benchmark --profile=small --output=results.csv
The benchmark program (main.go) assumes the cluster is already set up with VPA, KWOK, and the fake node. It then:
--noise-ratio > 0) — these are not managed by any VPAvpa_updater_execution_latency_seconds_sum metricse.g., of output using this command: bin/vpa-benchmark --profile=small,large,xxlarge
========== Results ==========
┌───────────────┬───────────────┬────────────────┬───────────────────┐
│ STEP │ SMALL ( 25 ) │ LARGE ( 250 ) │ XXLARGE ( 1000 ) │
├───────────────┼───────────────┼────────────────┼───────────────────┤
│ AdmissionInit │ 0.0000s │ 0.0001s │ 0.0004s │
│ EvictPods │ 2.4239s │ 24.5535s │ 98.6963s │
│ FilterPods │ 0.0002s │ 0.0020s │ 0.0925s │
│ ListPods │ 0.0001s │ 0.0006s │ 0.0025s │
│ ListVPAs │ 0.0024s │ 0.0030s │ 0.0027s │
│ total │ 2.4267s │ 24.5592s │ 98.7945s │
└───────────────┴───────────────┴────────────────┴───────────────────┘
We can then compare the results of a code change with the results of the main branch. Ideally the benchmark would be done on the same machine (or a similar one), with the same benchmark settings (profiles and runs).
| Profile | VPAs | ReplicaSets | Pods |
|---|---|---|---|
| small | 25 | 25 | 50 |
| medium | 100 | 100 | 200 |
| large | 250 | 250 | 500 |
| xlarge | 500 | 500 | 1000 |
| xxlarge | 1000 | 1000 | 2000 |
When --noise-percentage=P is set, each profile also creates P% additional noise ReplicaSets (not managed by any VPA). For example, --profile=medium --noise-percentage=50 creates 100 managed RS (200 pods) + 50 noise RS (100 pods) = 300 total pods.
| Flag | Default | Description |
|---|---|---|
--profile | small | Comma-separated profiles to run. You can run multiple profiles at once. (e.g., --profile=small,medium) |
--runs | 1 | Iterations per profile. This is used for averaging multiple runs. |
--output | "" | Path to output file for results table (CSV format). Output will always be printed to stdout. |
--kubeconfig | "" | Path to kubeconfig. Required if not using KUBECONFIG env var or ~/.kube/config. |
--noise-percentage | 0% | Percentage of additional noise (unmanaged) ReplicaSets relative to managed ReplicaSets. Set to 0% for no noise. Noise pods increase FilterPods and ListPods costs without adding VPAs. |
| Metric | Description |
|---|---|
ListVPAs | List VPA objects |
ListPods | List pods matching VPA targets |
FilterPods | Filter evictable pods |
AdmissionInit | Verify admission controller status |
EvictPods | Evict pods needing updates |
total | Total loop time |
| Script | Purpose |
|---|---|
hack/full-benchmark.sh | Full local workflow (Kind + VPA + KWOK + configure + benchmark) |
hack/install-kwok.sh | Install KWOK controller and create fake node |
hack/values.yaml | Helm values for benchmark-specific VPA configuration |
Environment variables accepted by the scripts:
| Variable | Default | Used by |
|---|---|---|
KWOK_VERSION | v0.7.0 | install-kwok.sh |
KWOK_NAMESPACE | kube-system | install-kwok.sh |
KWOK_NODE_NAME | kwok-node | install-kwok.sh |
VPA_NAMESPACE | kube-system | configure-vpa.sh |
KIND_CLUSTER_NAME | kind | full-benchmark.sh |
kind delete cluster
The benchmark includes several performance optimizations:
values.yaml configures VPA components via Helm:
--kube-api-qps=100 and --kube-api-burst=200 on all three components--updater-interval=2m on the updater (default is 60s)--memory-saver=true on the recommendernodeName, bypassing the scheduler for faster creationkubeadmConfigPatches to the base .github/kind-config.yaml to increase API server limits (max-requests-inflight, max-mutating-requests-inflight) and kube-controller-manager client QPS to handle the large number of API callstime.Tick which waits the full interval before the first tick, so the benchmark sleeps 2 minutes before polling for metrics