Green Cloud: AWS Sustainability Best Practices - Complete Guide 2024
Master AWS sustainability with a comprehensive guide covering carbon footprint reduction, Graviton processors, energy-efficient architectures, and green cloud strategies. Learn actionable best practices with 8+ code examples.
Introduction: Why Cloud Sustainability Matters
Climate change is no longer a distant concern—it's a business imperative. Data centers consume approximately 1-2% of global electricity, and cloud computing's explosive growth demands a conscious approach to energy consumption. The AWS Sustainability pillar of the Well-Architected Framework provides a roadmap for organizations to minimize their environmental impact while often reducing costs simultaneously.
This comprehensive guide explores every dimension of sustainable cloud architecture, from understanding carbon footprint fundamentals to implementing Graviton processors, optimizing storage, and leveraging serverless technologies. Whether you're a cloud architect, DevOps engineer, or sustainability officer, this 3000+ word deep dive will equip you with production-ready strategies and code examples to build genuinely sustainable AWS workloads.
Part 1: Sustainability Fundamentals and Carbon Footprint
Understanding the AWS Sustainability Pillar
The Sustainability pillar focuses on minimizing environmental impact by designing systems that maximize efficiency, minimize waste, and operate on renewable energy. AWS divides responsibility into two domains:
AWS's Responsibility:
- Building energy-efficient data centers
- Investing in renewable energy (AWS committed to 80% renewable energy by 2024)
- Optimizing hardware lifecycle management
- Continuously improving infrastructure efficiency
Your Responsibility:
- Designing efficient architectures
- Right-sizing compute resources
- Implementing proper monitoring and optimization
- Making informed regional and service selection decisions
Measuring Your Carbon Footprint
Understanding your environmental impact is the first step toward improvement. AWS provides several tools:
Using the AWS Customer Carbon Footprint Tool
The Customer Carbon Footprint Tool in your AWS Billing Console shows your emissions broken down by:
- Service (EC2, RDS, S3, Lambda, etc.)
- Region
- Time period
Here's how to programmatically retrieve carbon data using boto3:
import boto3
from datetime import datetime, timedelta
def get_carbon_footprint_metrics():
"""
Retrieve carbon footprint metrics from AWS Cost Explorer.
Requires CostExplorer permissions.
"""
ce_client = boto3.client('ce')
# Set date range (last 30 days)
end_date = datetime.now().date()
start_date = end_date - timedelta(days=30)
try:
response = ce_client.get_cost_and_usage(
TimePeriod={
'Start': start_date.strftime('%Y-%m-%d'),
'End': end_date.strftime('%Y-%m-%d')
},
Granularity='DAILY',
Metrics=['BlendedCost'],
GroupBy=[
{
'Type': 'DIMENSION',
'Key': 'SERVICE'
},
{
'Type': 'DIMENSION',
'Key': 'REGION'
}
],
Filter={
'Tags': {
'Key': 'Environment',
'Values': ['production']
}
}
)
# Parse results to calculate carbon intensity
results = {}
for result in response['ResultsByTime']:
for group in result['Groups']:
service = group['Keys'][0]
region = group['Keys'][1]
cost = float(group['Metrics']['BlendedCost']['Amount'])
if service not in results:
results[service] = {}
if region not in results[service]:
results[service][region] = 0
results[service][region] += cost
return results
except Exception as e:
print(f"Error retrieving carbon metrics: {e}")
return None
# Use the data to identify high-carbon services
metrics = get_carbon_footprint_metrics()
if metrics:
for service, regions in sorted(metrics.items(),
key=lambda x: sum(x[1].values()),
reverse=True)[:5]:
total_cost = sum(regions.values())
print(f"{service}: ${total_cost:.2f}")
Carbon Intensity by AWS Region
AWS regions have different carbon footprints based on their energy sources. Some regions leverage significant renewable energy:
Low-Carbon Regions (High Renewable Energy):
- Oregon (us-west-2) - ~35% renewable
- Canada (ca-central-1) - ~90% hydroelectric
- Stockholm (eu-north-1) - ~100% renewable
- Paris (eu-west-1) - ~95% renewable and nuclear
Higher-Carbon Regions:
- Sydney (ap-southeast-2)
- Mumbai (ap-south-1)
When possible, deploy workloads to low-carbon regions. However, data residency and latency requirements often take priority. The strategy is to optimize within your regional constraints.
Part 2: AWS Graviton Processors - The Energy Efficiency Revolution
Understanding Graviton's Efficiency Advantage
AWS Graviton processors are custom-designed ARM-based CPUs that deliver superior energy efficiency compared to x86 alternatives. The benefits are significant:
- 40% Better Price/Performance compared to comparable x86 instances
- 60% Energy Reduction per compute operation
- Up to 3x Better Performance for specific workloads
- Broader Availability across EC2, RDS, ElastiCache, and Elasticsearch
Graviton Instance Types by Workload
EC2 Graviton Families:
- t4g/t4g.nano to t4g.2xlarge - Burstable, development/testing
- m7g/m7g.medium to m7g.metal - General purpose, web servers, app servers
- c7g/c7g.medium to c7g.metal - Compute optimized, batch processing, high-traffic APIs
- r7g/r7g.medium to r7g.metal - Memory optimized, databases, caching
- hpc7g - High-performance computing workloads
Migration Strategy: From x86 to Graviton
Here's a comprehensive Terraform configuration to provision a migration pilot with both x86 and Graviton instances for comparison:
# Terraform: EC2 Graviton Migration Pilot
provider "aws" {
region = "us-east-1"
}
variable "environment" {
default = "production"
}
# Security group for both instance types
resource "aws_security_group" "app" {
name = "app-sg-${var.environment}"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# x86 Instance for baseline comparison
resource "aws_instance" "x86_baseline" {
ami = data.aws_ami.amazon_linux_x86.id
instance_type = "m6i.xlarge"
subnet_id = aws_subnet.main.id
vpc_security_group_ids = [aws_security_group.app.id]
root_block_device {
volume_type = "gp3"
volume_size = 100
encrypted = true
delete_on_termination = true
}
monitoring = true
tags = {
Name = "x86-baseline"
Environment = var.environment
Type = "baseline"
}
user_data = base64encode(<<-EOF
#!/bin/bash
yum update -y
yum install -y amazon-cloudwatch-agent
# Install monitoring agent
EOF
)
}
# Graviton Instance for comparison
resource "aws_instance" "graviton_test" {
ami = data.aws_ami.amazon_linux_arm.id
instance_type = "m7g.xlarge"
subnet_id = aws_subnet.main.id
vpc_security_group_ids = [aws_security_group.app.id]
root_block_device {
volume_type = "gp3"
volume_size = 100
encrypted = true
delete_on_termination = true
}
monitoring = true
tags = {
Name = "graviton-test"
Environment = var.environment
Type = "graviton"
}
user_data = base64encode(<<-EOF
#!/bin/bash
yum update -y
yum install -y amazon-cloudwatch-agent
# Install monitoring agent
EOF
)
}
# CloudWatch Alarms for Cost and Performance Tracking
resource "aws_cloudwatch_metric_alarm" "x86_cpu_utilization" {
alarm_name = "x86-cpu-utilization-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
dimensions = {
InstanceId = aws_instance.x86_baseline.id
}
}
resource "aws_cloudwatch_metric_alarm" "graviton_cpu_utilization" {
alarm_name = "graviton-cpu-utilization-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
dimensions = {
InstanceId = aws_instance.graviton_test.id
}
}
# Data sources for latest AMIs
data "aws_ami" "amazon_linux_x86" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
data "aws_ami" "amazon_linux_arm" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-arm64-gp2"]
}
}
# VPC Setup
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "main" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
# Outputs
output "x86_instance_id" {
value = aws_instance.x86_baseline.id
}
output "graviton_instance_id" {
value = aws_instance.graviton_test.id
}
Part 3: Energy-Efficient Regions and Instance Types
Selecting Low-Carbon Regions
Your region selection should balance three factors:
- Carbon Intensity - Renewable energy percentage
- Data Residency - Regulatory compliance
- Latency Requirements - Application performance needs
Here's a CloudWatch dashboard approach to monitor efficiency across regions:
AWSTemplateFormatVersion: '2010-09-09'
Description: Cross-Region Sustainability Monitoring Dashboard
Resources:
SustainabilityDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName: AWS-Sustainability-Metrics
DashboardBody: !Sub |
{
"widgets": [
{
"type": "metric",
"properties": {
"metrics": [
[ "AWS/EC2", "CPUUtilization", { "stat": "Average" } ],
[ "AWS/RDS", "DatabaseConnections" ],
[ "AWS/Lambda", "Duration", { "stat": "Average" } ],
[ "AWS/S3", "BucketSizeBytes" ]
],
"region": "us-west-2",
"title": "Oregon Region (Low-Carbon) Metrics"
}
},
{
"type": "metric",
"properties": {
"metrics": [
[ "AWS/EC2", "CPUUtilization", { "stat": "Average" } ],
[ "AWS/RDS", "DatabaseConnections" ],
[ "AWS/Lambda", "Duration", { "stat": "Average" } ],
[ "AWS/S3", "BucketSizeBytes" ]
],
"region": "eu-north-1",
"title": "Stockholm Region (100% Renewable) Metrics"
}
}
]
}
Right-Sizing Instance Selection
Use AWS Compute Optimizer to identify oversized instances. Here's a Python script to audit your instance right-sizing opportunities:
import boto3
from collections import defaultdict
def audit_instance_right_sizing():
"""
Analyze EC2 instances for right-sizing opportunities using Compute Optimizer.
Calculate potential energy and cost savings.
"""
compute_optimizer = boto3.client('compute-optimizer')
ec2 = boto3.client('ec2')
# Get all EC2 recommendations
try:
recommendations = compute_optimizer.get_ec2_instance_recommendations()
except Exception as e:
print(f"Error: {e}")
return
over_provisioned = []
optimal = []
under_provisioned = []
for recommendation in recommendations.get('instanceRecommendations', []):
instance_id = recommendation['instanceName']
current_type = recommendation['currentInstanceType']
finding = recommendation['finding']
if finding == 'Overprovisioned':
over_provisioned.append({
'instance_id': instance_id,
'current_type': current_type,
'recommendations': recommendation.get('recommendationOptions', [])
})
elif finding == 'Optimized':
optimal.append(instance_id)
elif finding == 'Underprovisioned':
under_provisioned.append({
'instance_id': instance_id,
'current_type': current_type
})
# Calculate sustainability impact
print("=== EC2 Sustainability Right-Sizing Report ===\n")
print(f"Optimal Instances: {len(optimal)}")
print(f"Overprovisioned: {len(over_provisioned)}")
print(f"Underprovisioned: {len(under_provisioned)}\n")
total_potential_savings = 0
for item in over_provisioned:
print(f"Instance: {item['instance_id']} ({item['current_type']})")
for option in item['recommendations']:
recommended_type = option['instanceType']
savings = option.get('savingsOpportunity', {}).get('estimatedMonthlySavings', {})
print(f" → Recommend: {recommended_type}")
print(f" → Monthly Savings: ${savings.get('value', 0):.2f}")
total_potential_savings += float(savings.get('value', 0))
print(f"\nTotal Monthly Savings Opportunity: ${total_potential_savings:.2f}")
print(f"Annual Savings Opportunity: ${total_potential_savings * 12:.2f}")
if __name__ == "__main__":
audit_instance_right_sizing()
Part 4: Auto Scaling for Right-Sizing
Dynamic Scaling to Eliminate Waste
Auto Scaling Groups automatically adjust capacity based on demand, ensuring you're not running excess capacity during low-traffic periods. This dramatically reduces energy consumption and costs.
CloudFormation Template for Sustainable Auto Scaling
AWSTemplateFormatVersion: '2010-09-09'
Description: Sustainable Auto Scaling Architecture with Graviton
Parameters:
EnvironmentName:
Type: String
Default: production
DesiredCapacity:
Type: Number
Default: 2
MaxSize:
Type: Number
Default: 10
MinSize:
Type: Number
Default: 1
Resources:
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
ImageId: !Sub '${LatestArmAmi}'
InstanceType: t4g.medium # Graviton with burstable capacity
Monitoring:
Enabled: true
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Environment
Value: !Ref EnvironmentName
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier:
- !Ref Subnet1
- !Ref Subnet2
- !Ref Subnet3
LaunchTemplate:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
MinSize: !Ref MinSize
MaxSize: !Ref MaxSize
DesiredCapacity: !Ref DesiredCapacity
HealthCheckType: ELB
HealthCheckGracePeriod: 300
Tags:
- Key: Name
Value: SustainableAutoScalingGroup
PropagateAtLaunch: true
# Target Tracking Scaling Policy - Aggressive Scale-Down
ScaleDownPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AdjustmentType: ChangeInCapacity
AutoScalingGroupName: !Ref AutoScalingGroup
Cooldown: 300
EstimatedWarmupSeconds: 300
CPUTargetTrackingScaling:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
PolicyType: TargetTrackingScaling
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ASGAverageCPUUtilization
TargetValue: 50 # Lower target = more aggressive scale-down
RequestCountTargetTracking:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
PolicyType: TargetTrackingScaling
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ALBRequestCountPerTarget
TargetValue: 1000 # Requests per instance
ScheduledScaleDown:
Type: AWS::AutoScaling::ScheduledAction
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
MinSize: 1
MaxSize: 5
DesiredCapacity: 1
Recurrence: '0 22 * * *' # 10 PM daily - off-peak scaling
ScheduledScaleUp:
Type: AWS::AutoScaling::ScheduledAction
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
MinSize: !Ref MinSize
MaxSize: !Ref MaxSize
DesiredCapacity: !Ref DesiredCapacity
Recurrence: '0 6 * * 1-5' # 6 AM weekdays - business hours scaling
Outputs:
AutoScalingGroupName:
Value: !Ref AutoScalingGroup
LaunchTemplateId:
Value: !Ref LaunchTemplate
Part 5: Reserved Instances and Savings Plans Impact
Long-Term Commitment Benefits
Reserved Instances and Savings Plans provide significant discounts while also promoting sustainability by encouraging predictable, consolidated workloads:
- Reserved Instances: 1-year or 3-year commitments = 30-72% savings
- Savings Plans: Flexible across instance family/size = 20-50% savings
- Spot Instances: 70-90% savings but with interruption risk
Here's a tool to analyze your commitment strategy:
import boto3
from datetime import datetime, timedelta
def analyze_commitment_opportunities():
"""
Analyze Reserved Instance and Savings Plan opportunities
to optimize for cost AND sustainability.
"""
ce_client = boto3.client('ce')
# Analyze on-demand costs over last 90 days
end_date = datetime.now().date()
start_date = end_date - timedelta(days=90)
response = ce_client.get_cost_and_usage(
TimePeriod={
'Start': start_date.strftime('%Y-%m-%d'),
'End': end_date.strftime('%Y-%m-%d')
},
Granularity='MONTHLY',
Metrics=['UnblendedCost'],
GroupBy=[
{'Type': 'DIMENSION', 'Key': 'INSTANCE_TYPE'},
{'Type': 'DIMENSION', 'Key': 'REGION'}
],
Filter={
'Dimensions': {
'Key': 'PURCHASE_TYPE',
'Values': ['On Demand']
}
}
)
print("=== Commitment Opportunity Analysis ===\n")
print(f"Analysis Period: {start_date} to {end_date}\n")
total_on_demand = 0
instance_costs = {}
for result in response['ResultsByTime']:
for group in result['Groups']:
instance_type = group['Keys'][0]
region = group['Keys'][1]
cost = float(group['Metrics']['UnblendedCost']['Amount'])
key = f"{instance_type}-{region}"
if key not in instance_costs:
instance_costs[key] = 0
instance_costs[key] += cost
total_on_demand += cost
# Calculate RI/Savings Plan benefits
print("Top On-Demand Costs (candidates for commitment)::\n")
total_potential_savings = 0
for key, cost in sorted(instance_costs.items(),
key=lambda x: x[1],
reverse=True)[:10]:
instance_type, region = key.split('-')
# Estimated savings with 3-year RI (70% discount)
ri_3yr_savings = cost * 0.70
# Estimated savings with 1-year RI (50% discount)
ri_1yr_savings = cost * 0.50
# Estimated savings with Savings Plan (45% discount)
sp_savings = cost * 0.45
print(f"{instance_type} in {region}")
print(f" 3-Month Cost: ${cost:.2f}")
print(f" 3-Year RI Savings: ${ri_3yr_savings:.2f}/month")
print(f" 1-Year RI Savings: ${ri_1yr_savings:.2f}/month")
print(f" Savings Plan Savings: ${sp_savings:.2f}/month\n")
total_potential_savings += ri_3yr_savings
annual_saving = total_potential_savings * 12
print(f"Annual Potential Savings (3-Year RI): ${annual_saving:,.2f}")
print(f"Sustainability Impact: Consolidated, predictable workloads")
if __name__ == "__main__":
analyze_commitment_opportunities()
Part 6: Data Transfer Optimization
Reducing Network Carbon Footprint
Data transfer consumes energy—both within AWS infrastructure and for internet egress. Strategies to reduce transfer:
AWS CLI Example: Identify High Data Transfer Costs
#!/bin/bash
# Analyze data transfer costs by service and region
aws ce get-cost-and-usage \
--time-period Start=2024-01-01,End=2024-01-31 \
--granularity MONTHLY \
--metrics "UnblendedCost" "UsageQuantity" \
--group-by Type=DIMENSION,Key=SERVICE Type=DIMENSION,Key=REGION \
--filter file://filter.json \
--query 'ResultsByTime[0].Groups[?contains(Keys[0], DataTransfer)].[Keys, Metrics]' \
--output table
# filter.json contents:
# {
# "Dimensions": {
# "Key": "PURCHASE_TYPE",
# "Values": ["Data Transfer"]
# }
# }
CloudFront and VPC Endpoints for Efficiency
AWSTemplateFormatVersion: '2010-09-09'
Resources:
# S3 bucket for content distribution
ContentBucket:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
# CloudFront distribution to reduce egress data transfer
CDNDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
DefaultCacheBehavior:
ViewerProtocolPolicy: https-only
AllowedMethods: [GET, HEAD]
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # Managed-CachingOptimized
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${CloudFrontOAI}'
TargetOriginId: S3Origin
Origins:
- Id: S3Origin
DomainName: !GetAtt ContentBucket.DomainName
S3OriginConfig: {}
CacheBehaviors:
- PathPattern: '*.jpg'
ViewerProtocolPolicy: https-only
Compress: true
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
TargetOriginId: S3Origin
# VPC Endpoint for S3 - eliminates internet gateway data transfer
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref VPC
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
RouteTableIds:
- !Ref PrivateRouteTable
Part 7: Storage Efficiency and Lifecycle Policies
Tiered Storage Strategy
Implement automatic storage tiering to move data to cheaper, more energy-efficient storage classes as it ages.
Comprehensive S3 Lifecycle Configuration
{
"Rules": [
{
"Id": "TransitionToIA",
"Status": "Enabled",
"Prefix": "logs/",
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "INTELLIGENT_TIERING"
},
{
"Days": 365,
"StorageClass": "GLACIER_IR"
},
{
"Days": 2555,
"StorageClass": "DEEP_ARCHIVE"
}
],
"Expiration": {
"Days": 2555
},
"NoncurrentVersionTransitions": [
{
"NoncurrentDays": 30,
"StorageClass": "STANDARD_IA"
},
{
"NoncurrentDays": 90,
"StorageClass": "GLACIER_IR"
}
],
"NoncurrentVersionExpiration": {
"NoncurrentDays": 365
}
},
{
"Id": "DeleteIncompleteMultipartUploads",
"Status": "Enabled",
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
},
{
"Id": "DeleteOldVersions",
"Status": "Enabled",
"NoncurrentVersionExpiration": {
"NoncurrentDays": 90
}
}
]
}
Data Compression and Deduplication
Compressed data transfers consume less energy. Use S3 server-side compression or application-level compression:
import boto3
import gzip
import io
def upload_compressed_object(bucket_name, key, data):
"""
Upload compressed data to S3 for reduced transfer and storage costs.
"""
s3_client = boto3.client('s3')
# Compress data
buf = io.BytesIO()
with gzip.GzipFile(fileobj=buf, mode='wb') as gz:
if isinstance(data, str):
gz.write(data.encode('utf-8'))
else:
gz.write(data)
compressed_data = buf.getvalue()
original_size = len(data.encode('utf-8') if isinstance(data, str) else data)
compressed_size = len(compressed_data)
# Upload to S3
s3_client.put_object(
Bucket=bucket_name,
Key=key,
Body=compressed_data,
ContentEncoding='gzip',
ContentType='application/json',
Metadata={
'original-size': str(original_size),
'compressed-size': str(compressed_size),
'compression-ratio': f"{(1 - compressed_size/original_size)*100:.1f}%"
}
)
print(f"Uploaded {key}")
print(f"Original: {original_size:,} bytes")
print(f"Compressed: {compressed_size:,} bytes")
print(f"Savings: {(1 - compressed_size/original_size)*100:.1f}%")
Part 8: Container and Serverless Optimization
ECS Optimization for Sustainability
Use Fargate with appropriate CPU/memory combinations to avoid overprovisioning:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: sustainable-cluster
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: sustainable-app
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: '256' # Minimal CPU for many workloads
Memory: '512' # Match to actual requirements
ContainerDefinitions:
- Name: app
Image: my-app:latest
Essential: true
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
Environment:
- Name: LOG_LEVEL
Value: INFO
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref ECSCluster
TaskDefinition: !Ref TaskDefinition
DesiredCount: 2
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
Subnets:
- !Ref PrivateSubnet
# Auto Scaling
ServiceScaling:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MaxCapacity: 10
MinCapacity: 1
ResourceId: !Sub 'service/${ECSCluster}/${Service.Name}'
RoleARN: !GetAtt ECSScalingRole.Arn
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
CpuScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: cpu-scaling
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref ServiceScaling
TargetTrackingScalingPolicyConfiguration:
TargetValue: 60
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageCPUUtilization
ScaleDownBehavior:
AdjustmentType: PercentChangeInCapacity
Cooldown: 60
Lambda for Serverless Sustainability
Lambda is inherently sustainable—you pay only for compute used, and AWS manages infrastructure efficiency:
import json
import boto3
import time
from datetime import datetime
def lambda_handler(event, context):
"""
Sustainable Lambda function with efficient resource usage.
- Uses minimal memory allocation
- Exits early to minimize execution time
- Implements connection pooling for database queries
"""
start_time = time.time()
# Initialize AWS clients (reuse connections)
s3 = boto3.client('s3')
dynamodb = boto3.resource('dynamodb')
try:
# Process event efficiently
bucket = event.get('bucket')
key = event.get('key')
if not bucket or not key:
return {
'statusCode': 400,
'body': json.dumps('Missing bucket or key')
}
# Get object efficiently with range queries
response = s3.get_object(Bucket=bucket, Key=key)
# Process in streaming fashion to minimize memory
lines_processed = 0
for line in response['Body'].iter_lines():
# Process each line without loading entire file
lines_processed += 1
# Store metrics for sustainability monitoring
table = dynamodb.Table('SustainabilityMetrics')
execution_time = time.time() - start_time
table.put_item(
Item={
'function_name': context.function_name,
'execution_time': execution_time,
'memory_used': context.memory_limit_in_mb,
'timestamp': datetime.utcnow().isoformat(),
'lines_processed': lines_processed,
'efficiency_ratio': lines_processed / execution_time
}
)
return {
'statusCode': 200,
'body': json.dumps({
'lines_processed': lines_processed,
'execution_time': execution_time,
'efficiency': f"{lines_processed/execution_time:.0f} lines/sec"
})
}
except Exception as e:
print(f"Error: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps(f'Error: {str(e)}')
}
Part 9: Database Optimization for Energy Efficiency
RDS with Graviton
Use Graviton-based RDS instances for significant energy and cost savings:
# Terraform: Graviton-based RDS PostgreSQL
resource "aws_db_instance" "sustainable_postgres" {
identifier = "sustainable-postgres-db"
engine = "postgres"
engine_version = "15.3"
instance_class = "db.r7g.xlarge" # Graviton3 memory-optimized
allocated_storage = 100
storage_type = "gp3"
iops = 3000
db_name = "appdb"
username = "admin"
password = random_password.db_password.result
multi_az = true
publicly_accessible = false
backup_retention_period = 30
backup_window = "03:00-04:00"
maintenance_window = "sun:04:00-sun:05:00"
storage_encrypted = true
kms_key_id = aws_kms_key.rds.arn
deletion_protection = true
skip_final_snapshot = false
final_snapshot_identifier = "sustainable-postgres-final-snapshot"
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.rds.id]
parameter_group_name = aws_db_parameter_group.optimized.name
# Enable Performance Insights for monitoring
performance_insights_enabled = true
performance_insights_retention_period = 7
tags = {
Name = "sustainable-postgres"
Environment = "production"
Type = "graviton"
}
}
resource "aws_db_parameter_group" "optimized" {
name = "sustainable-pg-params"
family = "postgres15"
# Efficient connection pooling
parameter {
name = "max_connections"
value = "100"
}
# Memory efficiency
parameter {
name = "shared_buffers"
value = "262144" # 2GB for r7g.xlarge
}
# Query optimization
parameter {
name = "random_page_cost"
value = "1.1"
}
# Log only slow queries
parameter {
name = "log_min_duration_statement"
value = "1000" # Log queries > 1 second
}
}
resource "aws_db_subnet_group" "main" {
name = "sustainable-db-subnet"
subnet_ids = [aws_subnet.private1.id, aws_subnet.private2.id]
}
Part 10: Monitoring and Reporting Carbon Metrics
Building a Sustainability Dashboard
Create CloudWatch dashboards specifically for sustainability metrics:
import boto3
import json
from datetime import datetime, timedelta
def create_sustainability_dashboard():
"""
Create comprehensive CloudWatch dashboard for sustainability metrics.
"""
cloudwatch = boto3.client('cloudwatch')
dashboard_body = {
"widgets": [
{
"type": "metric",
"properties": {
"metrics": [
["AWS/EC2", "CPUUtilization", {"stat": "Average"}],
["AWS/RDS", "CPUUtilization", {"stat": "Average"}],
["AWS/Lambda", "Duration", {"stat": "Average"}],
["Custom/Sustainability", "EnergyEfficiencyRatio"]
],
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "Resource Utilization Efficiency"
}
},
{
"type": "metric",
"properties": {
"metrics": [
["Custom/Sustainability", "GravitonInstanceCount"],
["Custom/Sustainability", "X86InstanceCount"],
["Custom/Sustainability", "ServerlessInvocations"]
],
"stat": "Average",
"region": "us-east-1",
"title": "Sustainable Architecture Metrics"
}
},
{
"type": "log",
"properties": {
"query": """
fields @timestamp, @message, instance_type, cpu_utilization
| stats avg(cpu_utilization) as avg_cpu by instance_type
| sort avg_cpu desc
""",
"region": "us-east-1",
"title": "CPU Efficiency by Instance Type"
}
}
]
}
cloudwatch.put_dashboard(
DashboardName='Sustainability-Dashboard',
DashboardBody=json.dumps(dashboard_body)
)
print("Created Sustainability Dashboard")
if __name__ == "__main__":
create_sustainability_dashboard()
Working with Warqline
We are a cloud engineering consultancy and an official AWS and Google Cloud partner. If you are running this in production and want a second pair of eyes, we scope work in a free 45-minute technical call: you describe what you are running and what worries you, and we tell you what we would look at first.
Conclusion: Building a Green Cloud Future
Sustainability is not a one-time optimization—it's a continuous practice. By implementing these strategies:
- Monitor relentlessly - Track carbon metrics alongside cost and performance
- Optimize continuously - Regular right-sizing and architecture reviews
- Embrace efficiency-first design - Choose Graviton, serverless, and auto-scaling by default
- Measure impact - Use AWS carbon tools and third-party solutions to quantify improvements
- Plan migrations - Systematically transition to more efficient compute options
The path to cloud sustainability is also the path to cost optimization and operational excellence. Organizations that build green cloud practices today gain competitive advantages tomorrow—lower costs, better efficiency, and positive environmental impact.
If you want help finding the quick wins and the longer-term ones in your own environment, talk to an engineer.