G
GuideDevOps
Lesson 11 of 12

Cloud Cost Optimization

Part of the Cloud Computing tutorial series.

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 5

Best 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.micro

Rightsizing Steps

  1. Monitor - CloudWatch for CPU, memory, network
  2. Analyze - AWS Compute Optimizer gives recommendations
  3. Test - Resize test instance first
  4. 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 metrics

Delete 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-xxx

Unattached 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-xxx

Unused 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-xxx

Storage 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.json

Compression

# Before uploading large files
gzip large-file.json
aws s3 cp large-file.json.gz s3://bucket/
 
# Saves ~80% storage cost

Database 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=Environment

Monitoring 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=SERVICE

Set Budget Alerts

# Alert if monthly spend > $5,000
aws budgets create-budget \
  --account-id 123456789 \
  --budget file://budget.json \
  --notifications-with-subscribers file://notifications.json

Cost 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