# Cloud Cost Optimization: The Practical Guide for AWS, Azure, and GCP

URL: https://www.devopsness.com/blog/cloud-cost-optimization-guide
Author: Kiril Urbonas
Published: 2026-07-15
Updated: 2026-10-12
Categories: Cloud
Tags: AWS, Cloud Cost, FinOps, Cloud, Cost Optimization

Summary: Cloud bills grow quietly until someone asks why. This is the map for cutting spend without cutting reliability: where the money actually goes, the levers that work, and the tools worth paying for.

---
# Cloud Cost Optimization: The Practical Guide for AWS, Azure, and GCP

Cloud bills rarely spike in a way anyone notices. They creep: a forgotten environment, an oversized instance family, egress nobody modeled, a logging pipeline ingesting ten times what anyone reads. By the time finance asks why the invoice doubled, the waste is spread across hundreds of line items. This is the map for finding that waste and cutting it without trading away reliability.

Cloud cost optimization is not one trick. It's a small number of high-impact levers applied in the right order, plus the discipline to keep them applied. When we spent a quarter on our own AWS bill, we cut it 38%; most of that came from a handful of changes and the rest from many small ones. The numbers below are from that pass, with a link to the deep dive for each lever.

## First, see where the money actually goes

You can't cut what you can't attribute. Before touching anything, get spend broken down by service, team, and environment, and set up alerting so the next spike shows up in hours, not on the invoice. That's covered in [catching AWS cost spikes before the invoice](/blog/aws-cost-anomaly-detection).

The usual shape once you can see it: compute is the biggest line, then data transfer and storage, then managed services and observability. Ours was EC2 at about 52% of the bill, RDS at 14%, S3 plus data transfer at 12%, and everything else 22%. Attribution only works if resources carry `team`, `environment`, and `project` tags, so enforce tagging and flag untagged resources; without it, accountability evaporates.

## Compute: right-size, then commit, then go spot

Compute is where the largest savings live, in three layers.

**Right-size first.** Most instances run at a fraction of their provisioned CPU and memory. We pulled 30 days of CloudWatch CPU, memory, and network metrics for 200+ EC2 instances and flagged anything under 30% p95 utilization on its bottleneck resource. Right-sizing often means a smaller instance in a newer generation: `m5.xlarge` to `m6i.large`, `c5.4xlarge` to `c6i.2xlarge`, `r5.2xlarge` to `r6i.xlarge`. That was our largest single change, about $8,000 a month. Every provider has a free recommender for this: AWS Compute Optimizer, GCP Recommender, and Azure Advisor.

**Commit to the steady state.** For the baseline you always run, commitments cut 30-70%. We put a 1-year compute Savings Plan over about 70% of baseline EC2 (around a 30% discount) and 1-year Reserved Instances on production RDS (around 40%), worth about $3,200 a month. We stay at one year because our workload changes; Savings Plans flex across instance types, so they survive later right-sizing better than RIs tied to a class. The tradeoffs are in [reserved instances vs savings plans vs spot](/blog/aws-reserved-savings-spot-when-each-fits). GCP's discounts work differently, explained in [committed use vs sustained use discounts](/blog/gcp-committed-use-discounts).

**Use spot for the interruptible parts.** Batch jobs, CI, and stateless workers can run 60-90% cheaper on spot if you handle interruptions, as in [running production on spot safely](/blog/spot-instances-guide). On EKS we run batch and async worker pools 100% on spot, web pools at 50/50, and stateful pools on-demand only, with Karpenter provisioning spot, draining nodes on the 2-minute interruption notice, and falling back to on-demand when capacity runs out. We see about two interruptions a week, and the change saved about $4,500 a month.

Which provider is cheapest for your mix is its own question, answered with real numbers in [AWS vs Azure vs GCP pricing](/blog/aws-vs-azure-vs-gcp-pricing).

## Storage and data transfer: the quiet line items

Storage looks cheap per GB and adds up fast, and pricing differs enough between providers to matter, compared in [S3 vs Azure Blob vs GCS](/blog/s3-vs-azure-blob-vs-gcs). Lifecycle rules from day one prevent most of it. On about 40TB of S3, we moved logs to Glacier Instant Retrieval after 30 days and Deep Archive after a year, backups to Glacier after 90 days, and deleted build artifacts after 180 days: about $600 a month, growing with every month of retention. Set CloudWatch Logs retention too, since log groups keep data forever by default; 30-90 days was another $200.

The bigger surprise is usually **egress**: cross-AZ, cross-region, and NAT gateway traffic that never appears in anyone's mental model until it's a large line. Our NAT gateway bill was about $2,800 a month, mostly one service downloading a 1.5GB ML model from S3 on every pod start. An S3 gateway endpoint routes that traffic around the NAT, and gateway endpoints carry no additional charge:

```bash
# find NAT-heavy traffic first, then route S3 around the NAT
$ aws ec2 create-vpc-endpoint \
    --vpc-id vpc-0abc123 \
    --vpc-endpoint-type Gateway \
    --service-name com.amazonaws.us-east-1.s3 \
    --route-table-ids rtb-0def456
```

We added interface endpoints for ECR image pulls, Secrets Manager, and SSM as well. Unlike gateway endpoints, interface endpoints are billed hourly plus data processing, so check the math per service; for us the endpoints together saved about $2,000 a month. Consolidating duplicate cross-region analytics copies and keeping a logging pipeline in-region added $500. The patterns are in [cloud egress costs explained](/blog/data-transfer-egress-costs).

## Managed services and zombies

Managed databases and caches get the same right-sizing treatment. RDS instances sized for "headroom" on `r5.4xlarge` fit on `r5.xlarge`; old `db.t2` moved to `db.t3` or Graviton `db.t4g`; databases on provisioned-IOPS `io1` that didn't need the IOPS moved to `gp3`. That was $1,200 a month. ElastiCache went from six `cache.r5.xlarge` nodes to three `cache.r6g.large`, another $700.

Zombies are small but free to fix: unattached EBS volumes, snapshots from terminated instances, manual RDS snapshots, load balancers with no targets, NAT gateways in unused test VPCs, old AMIs. We scripted a list of likely zombies, reviewed it by hand, and deleted about $400 a month.

```bash
# unattached EBS volumes: billed every month, attached to nothing
$ aws ec2 describe-volumes --filters Name=status,Values=available \
    --query 'Volumes[].[VolumeId,Size,CreateTime]' --output table
```

## Kubernetes: cost hides inside the cluster

A Kubernetes cluster is a cost black box unless you instrument it. Requests set too high waste the whole node; bin-packing and autoscaling recover it. The tools that surface and act on this (Kubecost, OpenCost, Cast AI) are compared in [Kubernetes cost optimization tools](/blog/kubernetes-cost-optimization-tools).

## The fastest wins, in order

When someone hands you a bloated bill and a week, this is the order that pays back fastest, detailed in [how to cut your AWS bill by 40%](/blog/how-to-reduce-aws-bill):

1. Check NAT and egress first. It was our biggest surprise, and the gateway-endpoint fix is mechanical.
2. Delete idle and orphaned resources.
3. Right-size the obvious over-provisioned instances and databases.
4. Kill or downsample runaway logging and observability ingestion.
5. Commit to the steady-state compute, then move stateless pools to spot.

## Four ideas that didn't pay off

**Forcing Graviton everywhere.** On our Java and Python services, some gained 10-20% performance and others saw nothing or slight regressions, while per-architecture images and dependencies cost real toil. We use it for new workloads instead.

**Scale-to-zero on steady workloads.** It saves money on genuinely bursty work; with a steady baseline it just churns.

**Multi-cloud price arbitrage.** Moving some workloads to GCP for cheaper pricing produced real but small savings, not worth the operational overhead for cost alone.

**Self-hosting to cut SaaS bills.** Replacing Datadog with self-hosted Grafana and Prometheus cut the invoice, but engineer time roughly matched it.

## Buy the right tooling, and keep the wins

Past a certain scale, spreadsheets stop working and a cost platform pays for itself by finding waste faster than a human can. The options (CloudZero, Vantage, Cast AI, and the native cost tools) are in [best FinOps and cloud cost tools](/blog/best-finops-tools).

The 38% cut was the easy part; costs creep back without a routine. Ours is a 30-minute monthly cost review, cost tracked per feature so anomalies get an owner, a cost estimate in any PR that adds major infrastructure (which catches a lot of "we don't need the bigger class"), and a quarterly pass through the recommender's high-confidence suggestions.

## The decision, concretely

- **No per-team cost breakdown yet?** Fix tagging and anomaly alerts before cutting anything.
- **High NAT or data transfer charges?** Add gateway endpoints and keep traffic in-region; it's the cheapest fix on the list.
- **Steady baseline compute?** Right-size first, then a 1-year commitment covering most of the baseline.
- **Stateless or batch workloads on on-demand?** Move them to spot with graceful drain and on-demand fallback.

## The call we'd make

Instrument spend first so every change is measurable, then work the levers in order: egress and zombies, right-sizing, commitments, spot, then the cluster. Make cost a standing metric with an owner, not a quarterly fire drill. The waste is almost never one big thing; it's fifty small things, and the teams that win are the ones who can see all fifty. The caveat is that every number above is from one AWS-heavy profile, so run the free recommender on your own bill before trusting anyone's percentages.

## Sources

- [AWS: Gateway endpoints for Amazon S3](https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-s3.html)
- [AWS: Create an interface VPC endpoint (pricing note)](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html)
- [AWS: CloudWatch Logs log groups and retention](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html)

