The Problem
Typical cloud spending breakdown:
- 30% - Services actually used
- 40% - Over-provisioned resources
- 20% - Unused resources
- 10% - Wasted due to inefficiency
Reserved Instances
Commit to usage for discount (1-year or 3-year)
Discount Structure
On-demand: $1.00/hour
1-year: $0.69/hour (31% discount)
3-year: $0.41/hour (59% discount)
AWS
# Check current usage
aws ce get-cost-and-usage \
--time-period Start=2024-01-01,End=2024-01-31 \
--metric "UnblendedCost" \
--granularity MONTHLY \
--group-by Type=DIMENSION,Key=PURCHASE_TYPE
# Purchase reserved instances
aws ec2 describe-reserved-instances-offerings \
--instance-type t2.micro \
--offering-class standard \
--filters Name=duration,Values=31536000 # 1 year in seconds
aws ec2 purchase-reserved-instances-offering \
--reserved-instances-offering-id xxx \
--instance-count 5Best Practices
✅ Buy RIs for baseline predictable workloads ✅ Use Savings Plans for flexibility ✅ Match RI terms to actual commitment ❌ Don't over-commit or under-utilize
Spot Instances
Buy unused capacity at 70-90% discount (risk: can be terminated)
# Cost comparison
On-demand t2.large: $0.094/hour
Spot t2.large: $0.028/hour (70% off)
# Request spot instance
aws ec2 request-spot-instances \
--spot-price 0.03 \
--instance-count 5 \
--type one-time \
--launch-specification '{"ImageId": "ami-xxx", "InstanceType": "t2.large"}'Use Cases
✅ Batch jobs (copying files, rendering) ✅ Data processing (NOT production APIs) ✅ Dev/test environments ✅ CI/CD pipelines ❌ NOT for databases or stateful services
Right-Sizing
Match instance type to actual needs
# Analyze current usage
aws ce get-reservation-purchase-recommendation \
--service "Amazon Elastic Compute Cloud - Compute" \
--lookback-period THIRTY_DAYS
# Common over-sizing
t2.large (2 vCPU, 8 GB RAM) running avg: 0.5 vCPU, 1 GB RAM # Could downsize to t2.microRightsizing Steps
- Monitor - CloudWatch for CPU, memory, network
- Analyze - AWS Compute Optimizer gives recommendations
- Test - Resize test instance first
- Schedule - Downsize during low-traffic window
# AWS Compute Optimizer
aws compute-optimizer get-ec2-instance-recommendations \
--instance-arns arn:aws:ec2:us-east-1:xxx:instance/i-xxx
# Response suggests smaller instance type with metricsDelete Unused Resources
Unattached EBS Volumes
# List all volumes
aws ec2 describe-volumes --query 'Volumes[?State==`available`].{ID:VolumeId,Size:Size,Created:CreateTime}'
# Delete unused
aws ec2 delete-volume --volume-id vol-xxxUnattached Elastic IPs
# Find unused IPs
aws ec2 describe-addresses --query 'Addresses[?AssociationId==null].{PublicIp:PublicIp,AllocationId:AllocationId}'
# Each unused EIP costs $0.005/hour (~$3.60/month)
aws ec2 release-address --allocation-id eipalloc-xxxUnused Load Balancers
# List ALBs with no target health
aws elbv2 describe-load-balancers \
--query 'LoadBalancers[?State.Code==`active`].{Name:LoadBalancerName,ARN:LoadBalancerArn}'
# Delete if not needed
aws elbv2 delete-load-balancer --load-balancer-arn arn:aws:elasticloadbalancing:...Old Snapshots
# List snapshots older than 30 days
aws ec2 describe-snapshots \
--owner-ids self \
--query "Snapshots[?StartTime<='2023-12-01'].{ID:SnapshotId,Created:StartTime,Size:VolumeSize}"
# Delete if no longer needed
aws ec2 delete-snapshot --snapshot-id snap-xxxStorage Optimization
S3 Lifecycle Policies
Automatically move to cheaper storage classes
cat > lifecycle.json << 'EOF'
{
"Rules": [
{
"Id": "archive-old",
"Filter": {"Prefix": "logs/"},
"Status": "Enabled",
"Transitions": [
{"Days": 30, "StorageClass": "STANDARD_IA"}, # $0.0125/GB
{"Days": 90, "StorageClass": "GLACIER"}, # $0.004/GB
{"Days": 180, "StorageClass": "DEEP_ARCHIVE"} # $0.00099/GB
],
"Expiration": {"Days": 365} # Delete after 1 year
}
]
}
EOF
aws s3api put-bucket-lifecycle-configuration --bucket logs-bucket --lifecycle-configuration file://lifecycle.jsonCompression
# Before uploading large files
gzip large-file.json
aws s3 cp large-file.json.gz s3://bucket/
# Saves ~80% storage costDatabase Optimization
RDS
# Downsize instance
aws rds modify-db-instance \
--db-instance-identifier mydb \
--db-instance-class db.t2.micro \
--apply-immediately
# Use aurora instead of RDS (cheaper)
# Aurora: $1/hour vs RDS: $2/hour (similar performance)DynamoDB
# Switch from provisioned to pay-per-request
aws dynamodb update-table \
--table-name Users \
--billing-mode PAY_PER_REQUEST
# If usage is unpredictable (saves cost)Networking Cost Reduction
Data Transfer Out
Average: $0.09/GB (most expensive)
# Use CloudFront CDN to cache
# CloudFront: $0.085/GB (slightly cheaper)
# Plus: Global distribution
# Direct data transfer between services in same region: FREE
# Data transfer between regions: $0.02/GB
Cross-Region Replication
# Only replicate if necessary
aws s3api put-bucket-replication \
--bucket source-bucket \
--replication-configuration file://replication.json
# Check: Is this replication necessary?Tagging and Cost Allocation
Track costs by project, team, or environment
# Tag resources
aws ec2 create-tags \
--resources i-xxx \
--tags Key=Environment,Value=Production Key=Team,Value=Platform Key=CostCenter,Value=123
# View costs by tag
aws ce get-cost-and-usage \
--time-period Start=2024-01-01,End=2024-01-31 \
--metric "UnblendedCost" \
--granularity DAILY \
--group-by Type=TAG,Key=EnvironmentMonitoring Spend
AWS Cost Explorer
# Get daily costs
aws ce get-cost-and-usage \
--time-period Start=2024-01-01,End=2024-01-31 \
--metric "UnblendedCost" \
--granularity DAILY
# By service
aws ce get-cost-and-usage \
--time-period Start=2024-01-01,End=2024-01-31 \
--metric "UnblendedCost" \
--granularity MONTHLY \
--group-by Type=DIMENSION,Key=SERVICESet Budget Alerts
# Alert if monthly spend > $5,000
aws budgets create-budget \
--account-id 123456789 \
--budget file://budget.json \
--notifications-with-subscribers file://notifications.jsonCost Optimization Checklist
✅ Use Reserved Instances for baseline workloads ✅ Use Spot Instances for non-critical workloads ✅ Right-size instances (monitor CPU/memory) ✅ Delete unused resources (EBS, EIPs, snapshots) ✅ implement S3 lifecycle policies ✅ Use CloudFront for content distribution ✅ Use Aurora instead of RDS (40-60% cheaper) ✅ Use DynamoDB pay-per-request if unpredictable ✅ Tag resources for cost tracking ✅ Monitor spend daily with AWS Cost Explorer ✅ Set budget alerts ✅ Review monthly and adjust