Kubernetes bills creep up quietly. Nodes get over-provisioned "just to be safe," forgotten workloads keep running, and nobody owns the cost. Here are five changes we apply on almost every AWS engagement — each is low-risk and measurable.

1. Right-size requests and limits

Most pods request far more CPU and memory than they use. Pull two weeks of usage from Prometheus and set requests close to the p95, not the peak.

# Top pods by CPU vs. their requests
kubectl top pods -A --sort-by=cpu

Rule of thumb: if cluster CPU requests are above 80% but actual usage is below 30%, you're paying for headroom you don't need.

2. Turn on the Cluster Autoscaler (or Karpenter)

Static node groups mean you pay for the busiest hour, all day. Karpenter provisions the cheapest instance that fits pending pods and removes nodes when they drain.

  • Bin-pack workloads onto fewer, larger nodes
  • Let Karpenter pick instance types and zones
  • Set a sensible consolidation policy

3. Use Spot for stateless workloads

Stateless services, CI runners and batch jobs are perfect for Spot instances at 60–90% off. Keep a small On-Demand base for critical pods and let the rest ride Spot with PodDisruptionBudgets for safety.

4. Delete the zombies

Every cluster has them: orphaned LoadBalancer services (each one an ELB you pay for), unattached EBS volumes, and old snapshots.

# Unattached EBS volumes
aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'Volumes[].VolumeId'

5. Make cost visible

You can't fix what nobody sees. Tag everything, then surface per-namespace cost with Kubecost or OpenCost on a Grafana dashboard the whole team looks at.


Done together, these typically take 30–40% off the bill in the first month — with no impact on reliability. The hard part isn't the tools, it's the discipline to keep doing it.

Want a free cost review of your cluster? Get in touch.