Kubernetes Cost Optimization
How to Cut Your Cloud Bill Without Cutting Corners

INTRODUCTION
Kubernetes is excellent at running workloads. It is also excellent at running up cloud bills in ways that are surprisingly hard to trace. We've walked into Kubernetes cost reviews where teams were spending three to five times more than necessary — not because of waste per se, but because the default Kubernetes configuration is not optimized for cost, and because the abstraction layers make cost attribution genuinely difficult.
The good news: Kubernetes cost optimization doesn't require radical architectural changes. The majority of savings come from a small number of practical interventions — many of which you can implement in a week. Here's the systematic approach we use.
Step 1: Get Visibility Before You Optimize
You cannot optimize what you cannot measure. The first step is always a cost attribution analysis that answers: which namespaces, which workloads, and which services are driving your cloud spending?
Kubernetes doesn't give you this out of the box. Cloud provider billing data shows you which EC2 instances or GKE nodes are costing money, but doesn't tell you which pods or deployments are responsible. You need a cost allocation layer on top.
Kubecost is the standard tool here — open-source (with a commercial tier for advanced features), it instruments your cluster and attributes costs to namespaces, deployments, labels, and teams. OpenCost is the CNCF-incubated alternative. Setup takes a few hours and immediately produces a ranked list of your most expensive workloads.
In almost every engagement, the cost attribution analysis reveals at least one or two workloads that are consuming a disproportionate share of resources — either due to misconfigured requests/limits, poorly scheduled batch jobs, or development workloads that should have been turned off.
Step 2: Fix Resource Requests and Limits
This is consistently where the largest savings come from, and it's also where Kubernetes configuration is most commonly wrong.
Kubernetes schedules pods based on resource requests (what the pod asks for) and enforces limits (the maximum it's allowed to use). When requests are set too high, pods claim more node capacity than they use — nodes fill up and new pods can't be scheduled even though there's actual compute headroom. You end up over-provisioning nodes to compensate.
The right sizing process: run Vertical Pod Autoscaler (VPA) in recommendation mode for 1–2 weeks across your cluster. VPA observes actual CPU and memory usage and generates recommendations for each workload. For most production workloads, actual usage is 30–60% of what's been requested. Right-sizing requests to reflect actual usage allows the cluster autoscaler to provision fewer nodes for the same workload.
One caution: for stateful applications and anything with spiky traffic patterns, leave meaningful headroom above the observed average. VPA recommendations are based on historical data and won't account for traffic spikes that exceed observed peaks.
Step 3: Autoscaling — All Three Kinds
Kubernetes has three distinct autoscaling mechanisms and most clusters only use one of them.
- Horizontal Pod Autoscaler (HPA) adds and removes pod replicas based on CPU, memory, or custom metrics. This is the most commonly implemented. The default metrics (CPU percentage) are adequate for many workloads but switching to business metrics (requests per second, queue depth) gives you much more precise scaling behavior.
- Vertical Pod Autoscaler (VPA) adjusts resource requests for individual pods based on observed usage. Running VPA in Auto mode (not just recommendation mode) automatically right-sizes pods over time — valuable for long-running workloads where traffic patterns evolve.
- Cluster Autoscaler adds and removes nodes based on whether pending pods can be scheduled. This is the most important for cost — it ensures you're not paying for idle nodes. Configure scale-down aggressively for non-production environments (minimum delay, minimum idle time before scale-down). In production, be more conservative about scale-down to maintain response time during traffic surges.
The compound effect of all three autoscalers working together is a cluster that dynamically right-sizes itself throughout the day — fewer nodes during off-peak hours, more during peak, with each node better utilized.
Step 4: Spot and Preemptible Instances
AWS Spot Instances and GCP Preemptible VMs run the same compute at 60–80% less than on-demand pricing. The tradeoff: they can be reclaimed by the cloud provider with 2 minutes' notice.
The key is matching workload characteristics to instance type. Spot is appropriate for: batch jobs, CI/CD workers, development and staging environments, stateless microservices with fast startup times and graceful shutdown, and worker nodes that process queue-based work. Spot is not appropriate for: stateful databases, coordination services (etcd), persistent PVs that can't be remounted quickly, and anything that can't tolerate a 2-minute disruption.
Karpenter (AWS) and the equivalent on GKE make Spot adoption dramatically easier than it used to be. Karpenter provisions nodes on-demand in response to pending pods and natively handles Spot interruptions by proactively draining and rescheduling workloads onto on-demand capacity. We typically run 60–80% Spot for eligible workloads and see 40–50% compute cost reductions on those node pools.
Step 5: Namespace Quotas and Cost Governance
Without governance, Kubernetes clusters tend toward resource sprawl. Developers request generous limits, test workloads never get cleaned up, and staging environments run 24/7 at production scale.
Namespace resource quotas set hard caps on total CPU and memory that can be allocated within a namespace. They're a forcing function for teams to be intentional about their resource usage and can prevent a single misconfigured deployment from consuming the entire cluster.
LimitRanges complement quotas by setting default requests and limits for pods that don't specify their own — eliminating the unlimited pod problem where a pod with no resource specification can consume unbounded resources.
For non-production environments: automated shutdown during off-hours. A simple CronJob or a tool like Kube-Downscaler that scales dev/staging deployments to zero replicas overnight and on weekends eliminates 50–70% of non-production compute spend with zero impact on development productivity.
What to Expect After Optimization
Based on our engagements, a focused 2–4 week Kubernetes cost optimization exercise typically yields 25–45% reduction in monthly cloud spend for clusters that haven't been actively optimized.
The breakdown usually looks something like: right-sizing resource requests (10–15% savings), Spot/Preemptible instances for eligible workloads (15–25% savings), dev/staging off-hours scheduling (5–10% savings), autoscaling improvements and idle node reduction (5–10% savings).
These aren't theoretical numbers — they're what we observe consistently. The one caveat: clusters that have already been through optimization passes will see smaller gains. If your team actively manages resource allocation, you're probably not leaving 40% on the table. But if you've never done a systematic review, you very likely are.