Most EKS clusters waste money the same way: application teams guess CPU and memory requests, then never revisit them. Requests that are too high leave nodes half empty. Requests that are too low get throttled or OOM-killed. On a Karpenter cluster this is worse, because node size follows pod requests. Bad requests create the wrong nodes.
Goldilocks does not magically set the perfect values. It uses Kubernetes Vertical Pod Autoscaler (VPA) in recommendation mode and shows you Guaranteed / Burstable starting points in a dashboard. You still apply the numbers in Helm charts or manifests.
This guide is the runbook I use to install it on EKS.
What you get
| Piece | Role |
|---|---|
| metrics-server | Exposes pod CPU and memory usage (kubectl top) |
| VPA recommender | Watches usage and writes a suggested request |
| Goldilocks controller | Creates a VPA object per workload in labeled namespaces |
| Goldilocks dashboard | Shows those suggestions in a UI |
Important: leave VPA updater and admission controller disabled. Goldilocks should recommend. It should not evict pods or rewrite live specs.
Prerequisites
kubectlpointed at the target EKS cluster- Helm 3
- Cluster-admin (or enough RBAC to install CRDs and cluster roles)
- EKS already running workloads you care about (recommendations need real traffic)
Connect:
aws eks update-kubeconfig --name cluster-name --region region-name kubectl get nodes
Example for a typical US cluster:
aws eks update-kubeconfig --name dev-cluster --region us-east-1
Step 1 — Confirm metrics-server
EKS usually already has metrics-server as an add-on.
kubectl get deployment metrics-server -n kube-system kubectl top nodes kubectl top pods -A | head
If metrics-server is missing:
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ helm repo update helm upgrade --install metrics-server metrics-server/metrics-server \ --namespace kube-system
Do not install a second metrics-server if one already exists. Two copies fight over the Metrics API.
Step 2 — Install VPA (recommender only)
Install VPA as its own Helm release so you can upgrade it independently of Goldilocks.
helm repo add fairwinds-stable https://charts.fairwinds.com/stable helm repo update helm upgrade --install vpa fairwinds-stable/vpa \ --namespace vpa \ --create-namespace \ --set recommender.enabled=true \ --set updater.enabled=false \ --set admissionController.enabled=false
Why those flags:
- recommender=true — this is the only component Goldilocks needs
- updater=false — no automatic pod restarts to apply new requests
- admissionController=false — no mutating webhook on every pod create
Wait until it is healthy:
kubectl get pods -n vpa kubectl get crd | grep verticalpodautoscaler
You should see CRDs such as verticalpodautoscalers.autoscaling.k8s.io.
Step 3 — Install Goldilocks
helm upgrade --install goldilocks fairwinds-stable/goldilocks \ --namespace goldilocks \ --create-namespace \ --set dashboard.enabled=true \ --set controller.enabled=true
Do not set vpa.enabled=true here if you already installed VPA in step 2. Two VPA installs will conflict.
Check pods:
kubectl get pods -n goldilocks kubectl get svc -n goldilocks
Expect a controller and a dashboard, both Running.
Step 4 — Opt in namespaces
Goldilocks is opt-in. Nothing is monitored until you label a namespace.
Do not label system namespaces:
kube-systemkarpentergoldilocksvpakube-publickube-node-lease
Label application namespaces:
kubectl get ns kubectl label namespace default goldilocks.fairwinds.com/enabled=true --overwrite kubectl label namespace <your-app-ns> goldilocks.fairwinds.com/enabled=true --overwrite
After a minute, VPAs appear:
kubectl get vpa -A
Each VPA should show updateMode: Off (recommend only). Confirm one:
kubectl get vpa -n <your-app-ns> -o yaml | grep -A2 updatePolicy
Step 5 — Open the dashboard
Port-forward is enough for a first look:
kubectl -n goldilocks port-forward svc/goldilocks-dashboard 8080:80
Open http://localhost:8080.
You will see namespaces you labeled, then workloads, then QoS columns (typically Guaranteed and Burstable) with suggested CPU and memory.
First-hour numbers are noisy. VPA needs hours to days of production-like traffic before the recommendation is trustworthy. Low-traffic namespaces will look empty or jumpy. That is expected.
How to use the numbers
Treat the dashboard as a starting point, not an auto-apply button.
A practical workflow:
- Pick a deployment that has run for at least a day under real load.
- Note Goldilocks Burstable CPU/memory (good default for most HTTP apps).
- Update
resources.requestsin Helm values or the Deployment. - Set limits only if you have a reason (memory limits prevent noisy-neighbor OOMs; CPU limits often cause throttling).
- Roll the deployment and watch p99 latency and restarts.
- Come back in a week.
On Karpenter, lower requests can shrink nodes. Apply changes in one namespace first, then watch kubectl get nodepool / node count before you roll this out everywhere.
Safety checklist
- VPA updater stays off.
- VPA admission webhook stays off.
- Goldilocks is not enabled on
kube-systemor Karpenter. - You are not running two metrics-servers.
- You wait for real traffic before trusting a recommendation.
- You change requests in Git / Helm, not by hand on a live pod.
If someone later enables updater.enabled=true, VPA will evict pods to apply new requests. That is a production incident waiting to happen. Keep it off unless you have a dedicated rightsizing program.
Optional: expose the dashboard inside the cluster
Port-forward is fine for admins. If you already have an ingress controller (ALB / NGINX), you can enable ingress on the Helm chart instead of leaving the UI on localhost.
Example values:
dashboard:
enabled: true
ingress:
enabled: true
ingressClassName: alb # or nginx
hosts:
- host: goldilocks.example.internal
paths:
- path: /
type: Prefix
Keep this on a private hostname or VPN. The dashboard is operational data, not a public site.
Uninstall
helm uninstall goldilocks -n goldilocks helm uninstall vpa -n vpa kubectl delete namespace goldilocks vpa
VPAs in labeled app namespaces may remain. Clean them if you are fully removing the tool:
kubectl delete vpa -A --all kubectl label namespace <your-app-ns> goldilocks.fairwinds.com/enabled-
Troubleshooting
Dashboard is empty
The namespace is not labeled, or the controller is not running. Check kubectl get pods -n goldilocks and kubectl get ns --show-labels.
No VPA objects
Controller RBAC failed, or the namespace label is missing. Check controller logs:
kubectl logs -n goldilocks deploy/goldilocks-controller
kubectl top fails
metrics-server is down or not installed. Goldilocks cannot work without it.
Recommendations look insane (tiny or huge)
The workload is idle, or it had a one-time spike. Wait for a full traffic cycle (weekday + peak) before changing production requests.
Pods restarting after install
You accidentally enabled the VPA updater or admission controller. Disable them immediately and roll back the Helm values in step 2.
Commands in one block
# kubeconfig aws eks update-kubeconfig --name <cluster-name> --region <region> # metrics-server check kubectl get deployment metrics-server -n kube-system kubectl top nodes # VPA (recommend only) helm repo add fairwinds-stable https://charts.fairwinds.com/stable helm repo update helm upgrade --install vpa fairwinds-stable/vpa \ --namespace vpa --create-namespace \ --set recommender.enabled=true \ --set updater.enabled=false \ --set admissionController.enabled=false # Goldilocks helm upgrade --install goldilocks fairwinds-stable/goldilocks \ --namespace goldilocks --create-namespace \ --set dashboard.enabled=true \ --set controller.enabled=true # opt in kubectl label namespace <your-app-ns> goldilocks.fairwinds.com/enabled=true --overwrite kubectl get vpa -A # UI kubectl -n goldilocks port-forward svc/goldilocks-dashboard 8080:80
Takeaway
Goldilocks is the missing feedback loop for Kubernetes resource requests on EKS. Install metrics-server (if needed), install VPA as a recommender only, install Goldilocks, label application namespaces, and wait for real traffic. Then change requests in Git.
The tool is cheap to run and expensive to misuse. Keep the updater off, skip system namespaces, and treat the dashboard as advice — not an autoscaler.