Cost Optimization That Sticks

Right-size before you commit, buy Savings Plans for your steady baseline, tag everything so you can see where the money goes, and let budgets warn you before the bill does.

Cloud spend rarely explodes in one dramatic moment. It creeps — an oversized instance here, a forgotten environment there. The senior move is to make cost visible and then attack it in the right order.

Right-size first, commit second

Never buy a discount for capacity you do not actually need. Look at Compute Optimizer and CloudWatch: if an m5.2xlarge sits at 8% CPU for a month, it wants to be an m5.large. Right-size the fleet, then price the steady-state.

Cover the baseline with Savings Plans

Whatever compute you run 24/7 is your baseline — buy a Compute Savings Plan for it (up to ~66% off on-demand) and let spiky, unpredictable load run on-demand. For fault-tolerant, interruptible work, Spot instances go up to ~90% off.

Tag everything, or fly blind

You cannot optimize what you cannot attribute. Enforce a tagging standard (Environment, Owner, CostCenter) and activate those as cost allocation tags so Cost Explorer can slice the bill by team and service.

Budgets are your smoke alarm

Set an AWS Budget with alerts at 50/80/100% of forecast. It is far cheaper to get an email on the 12th than a surprise invoice on the 1st.

Example

Example · json
{
  "BudgetName": "monthly-account-cap",
  "BudgetType": "COST",
  "TimeUnit": "MONTHLY",
  "BudgetLimit": { "Amount": "500", "Unit": "USD" },
  "CostFilters": {},
  "CostTypes": {
    "IncludeTax": true,
    "IncludeSubscription": true,
    "UseAmortized": true
  }
}

When to use it

  • A team saves 40% on steady-state EC2 by purchasing 1-year Compute Savings Plans while keeping 20% of capacity on-demand for bursts.
  • An engineer uses AWS Compute Optimizer to downsize 15 over-provisioned EC2 instances from m5.xlarge to m5.large, saving $800/month.
  • A startup enables S3 Intelligent-Tiering on their data lake bucket to automatically move cold objects to cheaper tiers without manual lifecycle rules.

More examples

Check Savings Plan Coverage

Shows what percentage of your on-demand compute is covered by Savings Plans each month, identifying gaps.

Example · bash
aws ce get-savings-plans-coverage \
  --time-period Start=2024-01-01,End=2024-04-01 \
  --granularity MONTHLY \
  --query 'SavingsPlansCoverages[].{Month:TimePeriod.Start,Coverage:Coverage.CoveragePercentage}' \
  --output table

List Unattached EBS Volumes

Finds EBS volumes not attached to any instance — these accrue storage costs with no value and should be deleted.

Example · bash
aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'Volumes[].{ID:VolumeId,Size:Size,Created:CreateTime,Type:VolumeType}' \
  --output table

Identify Idle EC2 Instances

Retrieves daily average CPU for an instance over 7 days; consistently low values indicate a candidate for rightsizing or termination.

Example · bash
aws cloudwatch get-metric-statistics \
  --namespace AWS/EC2 \
  --metric-name CPUUtilization \
  --dimensions Name=InstanceId,Value=i-0abc123 \
  --start-time $(date -d '7 days ago' --utc +%FT%TZ) \
  --end-time $(date --utc +%FT%TZ) \
  --period 86400 \
  --statistics Average \
  --query 'Datapoints[].{Date:Timestamp,CPU:Average}' \
  --output table

Discussion

  • Be the first to comment on this lesson.