Phase 74 β VPA Auto Mode
Phase 74 flips three VPA objects from updateMode: "Off" (recommendations only) to updateMode: "Auto" (VPA evicts and restarts pods to apply the recommended requests).
VPA was installed in Phase 70 (automation layer). After ~8 hours of live data, the recommendations were stable enough to enable Auto mode on stateless Deployments.
Decisions per Workloadβ
| Workload | Kind | New Mode | Reason |
|---|---|---|---|
backstage | Deployment | Auto | Recommendation (15m/380Mi) β current requests; safe stateless restart |
langfuse-web | Deployment | Auto | Had 8 OOMKill restarts; VPA will upsize memory to recommendation (1312Mi) |
litellm | Deployment | Auto | AI gateway; recommendation (100m/1312Mi) confirmed realistic |
langfuse-clickhouse | StatefulSet | Off | RWO PVC β forced eviction causes Multi-Attach conflict |
prometheus | Prometheus CRD | Off | CRD-managed StatefulSet; Prometheus operator manages pod lifecycle, VPA conflicts |
VPA Recommendations at the Time of Switch (8h data)β
backstage 15m CPU 380Mi RAM
langfuse-web 100m CPU 1312Mi RAM
litellm 100m CPU 1312Mi RAM
langfuse-clickhouse 1168m CPU 2539Mi RAM (StatefulSet β kept Off)
prometheus 11m CPU 50Mi RAM (capped by minAllowed: 200m/512Mi β kept Off)
The backstage VPA recommendation for CPU (15m) is below the minAllowed (100m), so VPA will apply 100m β same as the current Helm values. Effectively a no-op for CPU, with minor memory tuning.
How Auto Mode Worksβ
When updateMode: "Auto":
- VPA Admission Controller intercepts new pod creation and patches CPU/memory requests to match the recommendation.
- For existing running pods whose requests deviate significantly from the recommendation, VPA evicts the pod. Kubernetes restarts it, and the Admission Controller applies the new requests on startup.
Net effect: pods gradually get right-sized without human intervention. No HPA conflicts since none of these services use HPA.
:::caution Expect brief evictions
Enabling Auto on a running Deployment triggers an immediate eviction of pods whose requests are far from the recommendation. Plan for a 10β30 second restart on each affected service. For langfuse-web, this is desirable β it was OOMKilling and will come back with adequate memory.
:::
Gotcha β VPA Auto + short startup probesβ
When VPA Auto evicts a pod and it restarts, the Admission Controller applies the recommendation at pod creation. If the recommendation is very low (e.g. 15m CPU for Backstage based on steady-state usage) and the service has a slow startup, a tight startup probe window causes a restart loop:
VPA evicts pod β new pod starts with 15m CPU β Node.js takes 90s to start
β startup probe (failureThreshold:3, periodSeconds:10 = 30s window) expires
β kubelet kills pod β loop repeats
Fix applied for Backstage:
startupProbe.failureThreshold: 30(10s Γ 30 = 5 min window) β inbackstage-values.yamlminAllowed.cpu: 200mβ VPA never assigns requests below what Node.js needs to start
The general rule: set minAllowed.cpu to the CPU needed for startup, not for steady state. The startup probe window should be at least 2Γ the observed worst-case startup time. After startup completes, VPA sees the real steady-state usage and adjusts on the next eviction cycle β automatically, without manual intervention.
Configuration Changeβ
# manifests/vpa/00-vpa-objects.yaml β before:
updatePolicy:
updateMode: "Off"
# after (backstage, langfuse-web, litellm):
updatePolicy:
updateMode: "Auto"
Comments in the file document when Auto was enabled and the recommendation values at that time.
Monitoring VPA Activityβ
# See current recommendations:
kubectl get vpa -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,CPU:.status.recommendation.containerRecommendations[0].target.cpu,MEM:.status.recommendation.containerRecommendations[0].target.memory
# See VPA events (evictions):
kubectl get events -A --field-selector reason=EvictedByVPA
# Via Grafana β kube-prometheus-stack includes VPA dashboards
Upgrade Path β ClickHouse and Prometheusβ
ClickHouse (langfuse)β
ClickHouse runs as a StatefulSet with ReadWriteOnce Longhorn PVCs. VPA Auto would evict the pod, but the PVC can only attach to one node. If the evicted pod reschedules to a different node before the volume is released, it gets stuck in Multi-Attach error.
To safely enable Auto on ClickHouse:
- Manually right-size the StatefulSet to match the VPA recommendation (1168m/2539Mi)
- Keep VPA at Off for ongoing recommendations
- Or: migrate ClickHouse to a ReadWriteMany storage class (requires Longhorn RWX support)
Prometheusβ
The kube-prometheus-stack Prometheus operator owns the kube-prometheus-stack-prometheus StatefulSet and resets its resource requests on each reconcile loop. VPA Auto would fight the operator in a continuous loop. Keep VPA at Off for Prometheus and update resources via helm upgrade in helm-values/kube-prometheus-stack-values.yaml.