aws-cost-cleanup
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAWS Cost Cleanup
AWS成本清理
Automate the identification and removal of unused AWS resources to eliminate waste.
自动识别并移除未使用的AWS资源,消除资源浪费。
When to Use This Skill
何时使用该技能
Use this skill when you need to automatically clean up unused AWS resources to reduce costs and eliminate waste.
当你需要自动清理未使用的AWS资源以降低成本、减少浪费时,可以使用该技能。
Automated Cleanup Targets
自动清理目标
Storage
- Unattached EBS volumes
- Old EBS snapshots (>90 days)
- Incomplete multipart S3 uploads
- Old S3 versions in versioned buckets
Compute
- Stopped EC2 instances (>30 days)
- Unused AMIs and associated snapshots
- Unused Elastic IPs
Networking
- Unused Elastic Load Balancers
- Unused NAT Gateways
- Orphaned ENIs
存储
- 未挂载的EBS卷
- 超过90天的旧EBS快照
- S3未完成的分片上传任务
- 版本控制存储桶中的旧S3版本
计算
- 已停止超过30天的EC2实例
- 未使用的AMI及关联快照
- 未使用的弹性IP
网络
- 未使用的弹性负载均衡器
- 未使用的NAT网关
- 孤立的弹性网卡(ENI)
Cleanup Scripts
清理脚本
Safe Cleanup (Dry-Run First)
安全清理(先执行Dry-Run)
bash
#!/bin/bashbash
#!/bin/bashcleanup-unused-ebs.sh
cleanup-unused-ebs.sh
echo "Finding unattached EBS volumes..."
VOLUMES=$(aws ec2 describe-volumes
--filters Name=status,Values=available
--query 'Volumes[*].VolumeId'
--output text)
--filters Name=status,Values=available
--query 'Volumes[*].VolumeId'
--output text)
for vol in $VOLUMES; do
echo "Would delete: $vol"
Uncomment to actually delete:
aws ec2 delete-volume --volume-id $vol
done
```bash
#!/bin/bashecho "Finding unattached EBS volumes..."
VOLUMES=$(aws ec2 describe-volumes
--filters Name=status,Values=available
--query 'Volumes[*].VolumeId'
--output text)
--filters Name=status,Values=available
--query 'Volumes[*].VolumeId'
--output text)
for vol in $VOLUMES; do
echo "Would delete: $vol"
Uncomment to actually delete:
aws ec2 delete-volume --volume-id $vol
done
```bash
#!/bin/bashcleanup-old-snapshots.sh
cleanup-old-snapshots.sh
CUTOFF_DATE=$(date -d '90 days ago' --iso-8601)
aws ec2 describe-snapshots --owner-ids self
--query "Snapshots[?StartTime<='$CUTOFF_DATE'].[SnapshotId,StartTime,VolumeSize]"
--output text | while read snap_id start_time size; do
--query "Snapshots[?StartTime<='$CUTOFF_DATE'].[SnapshotId,StartTime,VolumeSize]"
--output text | while read snap_id start_time size; do
echo "Snapshot: $snap_id (Created: $start_time, Size: ${size}GB)"
Uncomment to delete:
aws ec2 delete-snapshot --snapshot-id $snap_id
done
```bash
#!/bin/bashCUTOFF_DATE=$(date -d '90 days ago' --iso-8601)
aws ec2 describe-snapshots --owner-ids self
--query "Snapshots[?StartTime<='$CUTOFF_DATE'].[SnapshotId,StartTime,VolumeSize]"
--output text | while read snap_id start_time size; do
--query "Snapshots[?StartTime<='$CUTOFF_DATE'].[SnapshotId,StartTime,VolumeSize]"
--output text | while read snap_id start_time size; do
echo "Snapshot: $snap_id (Created: $start_time, Size: ${size}GB)"
Uncomment to delete:
aws ec2 delete-snapshot --snapshot-id $snap_id
done
```bash
#!/bin/bashrelease-unused-eips.sh
release-unused-eips.sh
aws ec2 describe-addresses
--query 'Addresses[?AssociationId==null].[AllocationId,PublicIp]'
--output text | while read alloc_id public_ip; do
--query 'Addresses[?AssociationId==null].[AllocationId,PublicIp]'
--output text | while read alloc_id public_ip; do
echo "Would release: $public_ip ($alloc_id)"
Uncomment to release:
aws ec2 release-address --allocation-id $alloc_id
done
undefinedaws ec2 describe-addresses
--query 'Addresses[?AssociationId==null].[AllocationId,PublicIp]'
--output text | while read alloc_id public_ip; do
--query 'Addresses[?AssociationId==null].[AllocationId,PublicIp]'
--output text | while read alloc_id public_ip; do
echo "Would release: $public_ip ($alloc_id)"
Uncomment to release:
aws ec2 release-address --allocation-id $alloc_id
done
undefinedS3 Lifecycle Automation
S3生命周期自动化
bash
undefinedbash
undefinedApply lifecycle policy to transition old objects to cheaper storage
Apply lifecycle policy to transition old objects to cheaper storage
cat > lifecycle-policy.json <<EOF
{
"Rules": [
{
"Id": "Archive old objects",
"Status": "Enabled",
"Transitions": [
{
"Days": 90,
"StorageClass": "STANDARD_IA"
},
{
"Days": 180,
"StorageClass": "GLACIER"
}
],
"NoncurrentVersionExpiration": {
"NoncurrentDays": 30
},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}
EOF
aws s3api put-bucket-lifecycle-configuration
--bucket my-bucket
--lifecycle-configuration file://lifecycle-policy.json
--bucket my-bucket
--lifecycle-configuration file://lifecycle-policy.json
undefinedcat > lifecycle-policy.json <<EOF
{
"Rules": [
{
"Id": "Archive old objects",
"Status": "Enabled",
"Transitions": [
{
"Days": 90,
"StorageClass": "STANDARD_IA"
},
{
"Days": 180,
"StorageClass": "GLACIER"
}
],
"NoncurrentVersionExpiration": {
"NoncurrentDays": 30
},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}
EOF
aws s3api put-bucket-lifecycle-configuration
--bucket my-bucket
--lifecycle-configuration file://lifecycle-policy.json
--bucket my-bucket
--lifecycle-configuration file://lifecycle-policy.json
undefinedCost Impact Calculator
成本影响计算器
python
#!/usr/bin/env python3python
#!/usr/bin/env python3calculate-savings.py
calculate-savings.py
import boto3
from datetime import datetime, timedelta
ec2 = boto3.client('ec2')
import boto3
from datetime import datetime, timedelta
ec2 = boto3.client('ec2')
Calculate EBS volume savings
Calculate EBS volume savings
volumes = ec2.describe_volumes(
Filters=[{'Name': 'status', 'Values': ['available']}]
)
total_size = sum(v['Size'] for v in volumes['Volumes'])
monthly_cost = total_size * 0.10 # $0.10/GB-month for gp3
print(f"Unattached EBS Volumes: {len(volumes['Volumes'])}")
print(f"Total Size: {total_size} GB")
print(f"Monthly Savings: ${monthly_cost:.2f}")
volumes = ec2.describe_volumes(
Filters=[{'Name': 'status', 'Values': ['available']}]
)
total_size = sum(v['Size'] for v in volumes['Volumes'])
monthly_cost = total_size * 0.10 # $0.10/GB-month for gp3
print(f"Unattached EBS Volumes: {len(volumes['Volumes'])}")
print(f"Total Size: {total_size} GB")
print(f"Monthly Savings: ${monthly_cost:.2f}")
Calculate Elastic IP savings
Calculate Elastic IP savings
addresses = ec2.describe_addresses()
unused = [a for a in addresses['Addresses'] if 'AssociationId' not in a]
eip_cost = len(unused) * 3.65 # $0.005/hour * 730 hours
print(f"\nUnused Elastic IPs: {len(unused)}")
print(f"Monthly Savings: ${eip_cost:.2f}")
print(f"\nTotal Monthly Savings: ${monthly_cost + eip_cost:.2f}")
print(f"Annual Savings: ${(monthly_cost + eip_cost) * 12:.2f}")
undefinedaddresses = ec2.describe_addresses()
unused = [a for a in addresses['Addresses'] if 'AssociationId' not in a]
eip_cost = len(unused) * 3.65 # $0.005/hour * 730 hours
print(f"\nUnused Elastic IPs: {len(unused)}")
print(f"Monthly Savings: ${eip_cost:.2f}")
print(f"\nTotal Monthly Savings: ${monthly_cost + eip_cost:.2f}")
print(f"Annual Savings: ${(monthly_cost + eip_cost) * 12:.2f}")
undefinedAutomated Cleanup Lambda
自动清理Lambda函数
python
import boto3
from datetime import datetime, timedelta
def lambda_handler(event, context):
ec2 = boto3.client('ec2')
# Delete unattached volumes older than 7 days
volumes = ec2.describe_volumes(
Filters=[{'Name': 'status', 'Values': ['available']}]
)
cutoff = datetime.now() - timedelta(days=7)
deleted = 0
for vol in volumes['Volumes']:
create_time = vol['CreateTime'].replace(tzinfo=None)
if create_time < cutoff:
try:
ec2.delete_volume(VolumeId=vol['VolumeId'])
deleted += 1
print(f"Deleted volume: {vol['VolumeId']}")
except Exception as e:
print(f"Error deleting {vol['VolumeId']}: {e}")
return {
'statusCode': 200,
'body': f'Deleted {deleted} volumes'
}python
import boto3
from datetime import datetime, timedelta
def lambda_handler(event, context):
ec2 = boto3.client('ec2')
# Delete unattached volumes older than 7 days
volumes = ec2.describe_volumes(
Filters=[{'Name': 'status', 'Values': ['available']}]
)
cutoff = datetime.now() - timedelta(days=7)
deleted = 0
for vol in volumes['Volumes']:
create_time = vol['CreateTime'].replace(tzinfo=None)
if create_time < cutoff:
try:
ec2.delete_volume(VolumeId=vol['VolumeId'])
deleted += 1
print(f"Deleted volume: {vol['VolumeId']}")
except Exception as e:
print(f"Error deleting {vol['VolumeId']}: {e}")
return {
'statusCode': 200,
'body': f'Deleted {deleted} volumes'
}Cleanup Workflow
清理工作流
-
Discovery Phase (Read-only)
- Run all describe commands
- Generate cost impact report
- Review with team
-
Validation Phase
- Verify resources are truly unused
- Check for dependencies
- Notify resource owners
-
Execution Phase (Dry-run first)
- Run cleanup scripts with dry-run
- Review proposed changes
- Execute actual cleanup
-
Verification Phase
- Confirm deletions
- Monitor for issues
- Document savings
-
发现阶段(只读)
- 运行所有查询命令
- 生成成本影响报告
- 与团队共同评审
-
验证阶段
- 确认资源确实未被使用
- 检查依赖关系
- 通知资源所有者
-
执行阶段(先Dry-Run)
- 试运行清理脚本
- 评审拟执行的变更
- 执行实际清理操作
-
核验阶段
- 确认删除操作完成
- 监控是否出现问题
- 记录节省的成本
Safety Checklist
安全检查清单
- Run in dry-run mode first
- Verify resources have no dependencies
- Check resource tags for ownership
- Notify stakeholders before deletion
- Create snapshots of critical data
- Test in non-production first
- Have rollback plan ready
- Document all deletions
- 先运行Dry-Run模式
- 确认资源没有依赖
- 检查资源标签确认归属
- 删除前通知相关干系人
- 为关键数据创建快照
- 先在非生产环境测试
- 准备好回滚方案
- 记录所有删除操作
Example Prompts
示例提示词
Discovery
- "Find all unused resources and calculate potential savings"
- "Generate a cleanup report for my AWS account"
- "What resources can I safely delete?"
Execution
- "Create a script to cleanup unattached EBS volumes"
- "Delete all snapshots older than 90 days"
- "Release unused Elastic IPs"
Automation
- "Set up automated cleanup for old snapshots"
- "Create a Lambda function for weekly cleanup"
- "Schedule monthly resource cleanup"
发现类
- "查找所有未使用的资源并计算可节省的成本"
- "为我的AWS账户生成一份清理报告"
- "哪些资源我可以安全删除?"
执行类
- "创建一个清理未挂载EBS卷的脚本"
- "删除所有超过90天的快照"
- "释放未使用的弹性IP"
自动化类
- "为旧快照配置自动清理机制"
- "创建一个每周执行清理的Lambda函数"
- "调度每月一次的资源清理任务"
Integration with AWS Organizations
与AWS Organizations集成
bash
undefinedbash
undefinedRun cleanup across multiple accounts
Run cleanup across multiple accounts
for account in $(aws organizations list-accounts
--query 'Accounts[*].Id' --output text); do
--query 'Accounts[*].Id' --output text); do
echo "Checking account: $account"
aws ec2 describe-volumes
--filters Name=status,Values=available
--profile account-$account done
--filters Name=status,Values=available
--profile account-$account done
undefinedfor account in $(aws organizations list-accounts
--query 'Accounts[*].Id' --output text); do
--query 'Accounts[*].Id' --output text); do
echo "Checking account: $account"
aws ec2 describe-volumes
--filters Name=status,Values=available
--profile account-$account done
--filters Name=status,Values=available
--profile account-$account done
undefinedMonitoring and Alerts
监控与告警
bash
undefinedbash
undefinedCreate CloudWatch alarm for cost anomalies
Create CloudWatch alarm for cost anomalies
aws cloudwatch put-metric-alarm
--alarm-name high-cost-alert
--alarm-description "Alert when daily cost exceeds threshold"
--metric-name EstimatedCharges
--namespace AWS/Billing
--statistic Maximum
--period 86400
--evaluation-periods 1
--threshold 100
--comparison-operator GreaterThanThreshold
--alarm-name high-cost-alert
--alarm-description "Alert when daily cost exceeds threshold"
--metric-name EstimatedCharges
--namespace AWS/Billing
--statistic Maximum
--period 86400
--evaluation-periods 1
--threshold 100
--comparison-operator GreaterThanThreshold
undefinedaws cloudwatch put-metric-alarm
--alarm-name high-cost-alert
--alarm-description "Alert when daily cost exceeds threshold"
--metric-name EstimatedCharges
--namespace AWS/Billing
--statistic Maximum
--period 86400
--evaluation-periods 1
--threshold 100
--comparison-operator GreaterThanThreshold
--alarm-name high-cost-alert
--alarm-description "Alert when daily cost exceeds threshold"
--metric-name EstimatedCharges
--namespace AWS/Billing
--statistic Maximum
--period 86400
--evaluation-periods 1
--threshold 100
--comparison-operator GreaterThanThreshold
undefinedBest Practices
最佳实践
- Schedule cleanup during maintenance windows
- Always create final snapshots before deletion
- Use resource tags to identify cleanup candidates
- Implement approval workflow for production
- Log all cleanup actions for audit
- Set up cost anomaly detection
- Review cleanup results weekly
- 在维护窗口内调度清理任务
- 删除前务必创建最终快照
- 使用资源标签识别可清理的候选资源
- 生产环境实现审批工作流
- 记录所有清理操作用于审计
- 配置成本异常检测
- 每周评审清理结果
Risk Mitigation
风险缓解
Medium Risk Actions:
- Deleting unattached volumes (ensure no planned reattachment)
- Removing old snapshots (verify no compliance requirements)
- Releasing Elastic IPs (check DNS records)
Always:
- Maintain 30-day backup retention
- Use AWS Backup for critical resources
- Test restore procedures
- Document cleanup decisions
中风险操作:
- 删除未挂载的卷(确认没有计划重新挂载)
- 移除旧快照(确认没有合规保留要求)
- 释放弹性IP(检查DNS记录)
通用要求:
- 保留30天的备份周期
- 对关键资源使用AWS Backup
- 测试恢复流程
- 记录清理决策
Kiro CLI Integration
Kiro CLI集成
bash
undefinedbash
undefinedAnalyze and cleanup in one command
Analyze and cleanup in one command
kiro-cli chat "Use aws-cost-cleanup to find and remove unused resources"
kiro-cli chat "Use aws-cost-cleanup to find and remove unused resources"
Generate cleanup script
Generate cleanup script
kiro-cli chat "Create a safe cleanup script for my AWS account"
kiro-cli chat "Create a safe cleanup script for my AWS account"
Schedule automated cleanup
Schedule automated cleanup
kiro-cli chat "Set up weekly automated cleanup using aws-cost-cleanup"
undefinedkiro-cli chat "Set up weekly automated cleanup using aws-cost-cleanup"
undefined