Goldilocks and Vertical Pod Autoscaler: Right-Sizing Kubernetes Workloads
Every container in Kubernetes should declare resource requests (what it needs to be scheduled) and limits (the ceiling it can't exceed). In practice, most of these numbers get set once, early on, by guessing, and then never revisited. That guess is very often wrong in one of two directions, and both directions cost you something.
The two ways to get it wrong
Set requests too low, and the scheduler happily packs far more Pods onto a node than it can actually support once they're all under real load, leading to CPU throttling or, worse, the node running out of memory and the kernel killing Pods outright (an OOMKill). Set requests too high, and the scheduler reserves resources that never actually get used, meaning you're paying for capacity that just sits idle, sometimes very expensively at cluster scale across dozens of services.
The honest answer to "what should this Pod's requests be" is "whatever it actually uses in practice," which means you need real usage data, not a guess made before the application ever ran in production.
VerticalPodAutoscaler: Kubernetes' built-in answer
The VerticalPodAutoscaler (VPA) watches a workload's actual CPU and memory usage over time and can recommend, or in more aggressive modes automatically apply, better resource requests based on what it's observed. VPA has three distinct modes, and the difference between them matters a lot:
- Off: VPA only computes recommendations, doesn't touch anything. Useful for observing what it would suggest before trusting it with anything live.
- Initial: VPA sets resource requests only when a Pod is first created, based on historical data, but never touches a running Pod afterward.
- Auto (sometimes called Recreate): VPA actively evicts and recreates Pods with updated resource requests whenever its recommendation changes significantly.
That last mode is the one to be genuinely careful with. Recreating a Pod to change its resources means real disruption, and VPA in Auto mode doesn't currently coordinate with a HorizontalPodAutoscaler cleanly if both are targeting the same workload's CPU. For a lot of real-world use, VPA's recommendation-only capability is actually the most valuable part, independent of whether you ever let it auto-apply anything.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Off" # recommendation only, nothing auto-applied
Where Goldilocks comes in
Even in recommendation-only mode, VPA's output is a Kubernetes object you have to know to look for and interpret, not something anyone glances at casually. Goldilocks, an open-source tool from Fairwinds, solves exactly that usability gap: it automatically creates a VPA object in recommendation mode for every workload in a namespace you've opted in, and gives you a clean dashboard showing recommended requests and limits across your entire namespace at a glance, instead of having to kubectl describe individual VPA objects one at a time.
Enabling it for a namespace is a single label:
kubectl label namespace my-app goldilocks.fairwinds.com/enabled=true
From that point on, Goldilocks' controller watches every Deployment in that namespace, creates the underlying VPA objects for you automatically, and surfaces the recommendations through its dashboard.
Reading the recommendations: QoS in practice
Goldilocks presents its suggestions in terms of Kubernetes' Quality of Service classes, which is a genuinely useful framing:
- Guaranteed: requests equal limits, for both CPU and memory. The Pod gets exactly the resources it asked for, nothing more, nothing less, and is the last to be evicted under node pressure.
- Burstable: requests are lower than limits, giving the Pod room to use more when it's available, without reserving that extra headroom permanently.
Goldilocks shows you what your recommended requests/limits would look like under each philosophy, so you can make an informed choice per workload rather than applying the same policy blindly everywhere, a latency-sensitive service might warrant Guaranteed, while a batch job with bursty, predictable spikes might be a better fit as Burstable.
Why recommendation mode is the honest starting point
It's tempting to jump straight to VPA's Auto mode, or a policy of always trusting Goldilocks' numbers immediately, but resource usage patterns can be genuinely spiky and workload-specific. A recommendation based on a quiet week doesn't necessarily hold during a traffic spike three weeks later. The safer, and more common, real-world pattern is:
- Enable Goldilocks and VPA in recommendation mode.
- Watch recommendations over a meaningful window, at least a couple of weeks, ideally including a known peak-traffic period.
- Apply the suggested values manually, reviewing them the same way you'd review any other production configuration change.
- Only consider VPA's Auto mode for workloads where the disruption of a Pod restart is genuinely low-risk.
The actual payoff
Once requests and limits are set based on real observed data instead of a guess made on day one, two things typically improve at once: fewer OOMKills and throttling incidents (because requests weren't set too low), and lower cluster cost (because you're no longer reserving capacity nobody's using). Both directions of the original guessing problem get fixed by the same underlying fix, actual data replacing a guess.
If you want to test your grip on the resource management concepts underneath all of this, requests, limits, and QoS classes, the Kubernetes quiz on OpsQuiz covers exactly that ground.