The bill is bigger than the nodes
When the EKS line item grows, the first instinct is to look at EC2. That is a reasonable starting point, but it hides much of the story. NAT gateway processing, cross-zone transfer, application load balancers, EBS volumes, CloudWatch logs and idle development clusters can add up to a substantial share of the bill, and none of them show up as “Kubernetes”.
This page describes the analysis stage of our AWS EKS consulting. For a broader set of tactics read EKS cost optimisation: 12 ways, and you can run a quick estimate with our EKS cost calculator. This analysis feeds scaling configuration, where many of the savings are realised.
What good looks like
- You can answer “what does this team’s service cost per month” in minutes.
- Idle and orphaned resources are found by routine, not by accident.
- Pod requests reflect real usage with headroom, not guesses.
- Commitments (Savings Plans) cover the steady baseline, and variable load runs on flexible capacity.
- Someone reviews cost on a schedule and has the authority to act.
Step one: attribution
Without allocation, cost conversations turn into blame. We establish three views:
- AWS view: Cost and Usage Report or Cost Explorer grouped by tags such as environment, team and cluster.
- Kubernetes view: OpenCost or Kubecost mapping node and storage cost to namespaces, labels and workloads, based on requests and usage.
- Shared cost rules: how the control plane, system add-ons, monitoring and idle capacity are split. Idle capacity is shown separately so it is visible, not hidden in team numbers.
Tagging discipline is part of this. Terraform modules enforce tags on nodes, volumes and load balancers, as set out in Terraform modules and state.
Where waste usually hides
Oversized requests
The scheduler reserves capacity by pod requests. If a service requests 2 CPU and uses 0.2, the node is considered full while sitting mostly idle. Compare requests against observed usage over a representative window (including peaks) and adjust. A query like this shows CPU request versus use per namespace:
sum by (namespace) (kube_pod_container_resource_requests{resource="cpu"})
/
sum by (namespace) (rate(container_cpu_usage_seconds_total{container!=""}[7d]))
Run it against a long enough range for your traffic cycle. Treat results as a starting list for investigation, not automatic changes. The Vertical Pod Autoscaler in recommendation mode is a safe way to gather suggestions, and our glossary entry on requests and limits explains the mechanics.
Idle and over-provisioned nodes
Large fixed node groups sized for peak run all night. Moving to Karpenter with consolidation, or tuning Cluster Autoscaler, lets capacity follow demand. Non-production clusters can be scaled down or paused outside working hours.
Networking
- NAT gateways: per-gigabyte processing charges plus hourly cost. Gateway endpoints for S3 and interface endpoints for ECR and other services reduce it.
- Cross-zone traffic: chatty services across zones accumulate transfer charges. Topology-aware routing and placement help where the saving justifies the complexity.
- Load balancers: multiple ALBs per service can be consolidated behind a shared ingress.
Storage and observability
Unattached EBS volumes, old snapshots and oversized PVCs persist after workloads are gone. Verbose application logs shipped to CloudWatch or a hosted vendor can exceed compute cost. We review log levels, retention and metric cardinality, linking back to monitoring design.
Pricing levers compared
| Lever | Saves on | Trade-off |
|---|---|---|
| Right-sizing requests | Node count | Needs usage data, risk of throttling if cut too far |
| Autoscaling and consolidation | Idle capacity | Requires disruption tuning |
| Spot capacity | Compute unit price | Interruptions, needs replicas and diversity |
| Compute Savings Plans | Steady baseline price | Commitment, wrong sizing wastes the discount |
| Graviton instances | Price and efficiency per unit | Needs arm64 images and testing |
| Fargate | Node operations | Often costlier per unit at steady load |
We state assumptions for each estimate, because savings depend on your workload, traffic shape and risk tolerance. Where an option is not worth it for you, we say so.
A worked example: reading a namespace report
Imagine the allocation report shows one namespace consuming a large share of node cost, yet its pods show low CPU and memory use. The first question is whether the requests are inflated or whether the workload is bursty and the requests are protecting it. We compare usage percentiles over a full traffic cycle, including month-end or campaign peaks, rather than the average.
If the requests are simply copied from an old template, we lower them in stages and watch throttling and out-of-memory events. If the workload is genuinely bursty, the answer is different: keep modest requests, allow burst through limits where appropriate, and let node scaling absorb the spikes. Both outcomes are findings, and the second shows why a blanket cut would be a mistake.
Non-production environments
Development and staging clusters often cost more than expected because nothing ever switches them off. Options include scheduled scale-down, smaller node pools, shared clusters with namespace quotas, and short-lived preview environments that are deleted when a branch closes. Each saves differently, and we choose with your team based on how engineers actually work.
When optimisation is the wrong priority
If the system is unstable, fix reliability first: aggressive cost cutting on a fragile cluster creates outages that cost more than the saving. If spend is small relative to engineering time, a month of effort may not pay back. And if the real issue is a few runaway workloads or forgotten environments, a quick clean-up beats a programme.
Recommendations, ranked
The deliverable is a written plan. Each item lists the finding, evidence, estimated saving range with assumptions, effort, risk, owner and rollback. We sequence work so low-risk wins come first and invasive changes follow once the baseline is visible. We can implement the changes, or hand your team the plan; engagement models explain both.
Making it stick
One-off clean-ups decay. We set up a cost dashboard, budgets and anomaly alerts, tagging checks in CI, and a monthly review. For teams that want it handled continuously, managed DevOps includes regular cost reviews.
How to tell it is working
Unit cost trends (cost per request, per tenant or per environment) improve while reliability holds. Idle capacity share falls, unallocated cost shrinks and new spikes are explained within days. To start, book a consultation.