An AWS bill rarely grows because of one big decision. It grows through many small ones: a test server nobody switched off, a NAT gateway in the wrong place, logs that are kept indefinitely. This article lists the causes I see most often, and the AWS tools that show where the money goes.
First, find out where the money goes
Guessing is expensive; AWS has the tools to measure.
- AWS Cost Explorer breaks costs down by service, account, region and usage type, over time (AWS documentation).
- Cost allocation tags let you split costs by product, team or environment. Tag the resources, then activate the tags in the Billing console (AWS documentation). Without tags you can see that compute costs grew, but not which product caused it.
- AWS Budgets and Cost Anomaly Detection send an alert before the month is over, instead of a surprise when the invoice arrives (Budgets, Cost Anomaly Detection).
The usual causes
Resources nobody uses any more
A stopped server still pays for its disks. A detached EBS volume is charged until it is deleted (AWS documentation). Old snapshots, idle load balancers and forgotten test installations add up the same way. Public IPv4 addresses belong on this list too: AWS charges an hourly rate for every public IPv4 address, whether it is attached to a resource or not (AWS News Blog).
Oversized servers and databases
Instances are often sized for a peak that never came. AWS Compute Optimizer recommends sizes based on the actual utilisation (AWS documentation), and Cost Optimization Hub collects such recommendations across accounts and regions (AWS documentation).
Test environments that run like production
Development and staging environments often run around the clock, at production size, although they are used a few hours a day. A schedule that stops them outside working hours, smaller instances and fewer replicas outside production are among the simplest savings.
Network traffic: NAT gateways and data transfer
- A NAT gateway is charged for every hour it runs and for every gigabyte it processes, regardless of where the traffic goes, including to Amazon S3 in the same region (Amazon VPC pricing). For S3 and DynamoDB, a gateway VPC endpoint avoids that processing charge (AWS documentation).
- Traffic between Availability Zones is charged; traffic within the same zone is free (AWS Architecture Blog). Services that talk to each other a lot across zones make this visible on the bill.
- Data transfer out to the internet is charged per gigabyte beyond a monthly free allowance (Amazon EC2 pricing).
Storage that only grows
- CloudWatch Logs keeps log data indefinitely unless a retention period is set for the log group (AWS documentation).
- In S3, incomplete multipart uploads keep taking up storage until they are aborted; AWS recommends a lifecycle rule that aborts them (AWS documentation). Lifecycle rules can also move old data to cheaper storage classes.
- EBS volumes of type gp2 can be changed to gp3, which AWS prices up to 20% lower per gigabyte, without detaching them (AWS Storage Blog).
On-demand prices for steady usage
Savings Plans offer lower prices in exchange for a commitment to a consistent amount of usage for one or three years (AWS documentation). They pay off once the usage is stable and right-sized; a commitment made before the clean-up locks in the waste.
Kubernetes clusters with room to spare
In Kubernetes, the nodes are sized for what the applications request, not for what they use. Requests that were set generously once and never revisited leave much of the paid capacity idle.
Where to start
- Activate cost allocation tags and look at Cost Explorer by service and by tag.
- Set a budget with alerts and turn on Cost Anomaly Detection.
- Remove what is unused, set log retention, and change gp2 volumes to gp3.
- Right-size servers and databases; only then consider Savings Plans.
- Review the architecture: network paths, test environments, and whether several clouds or accounts could be consolidated.
An example
At Talk-A-Bot, the largest saving did not come from fine-tuning but from the architecture: the platform and its clients' projects ran on three clouds, Google Cloud, Azure and AWS, and were consolidated onto one AWS platform on Kubernetes. Infrastructure costs fell by 77%. The details are in the Talk-A-Bot case study.
Where I can help
I review costs and architecture, plan the savings and the migration, implement them as code, and hand over a setup your team can run. Changes to the application code stay with your developers.