AWS 成本清理

aws-cost-cleanup
分类通用
作者Agentic Awesome Skills 社区
许可MIT
评分4.60/5
使用3.4K

AWS 成本清理

自动化识别并删除未使用的 AWS 资源,以消除浪费。

何时使用此技能

当你需要自动清理未使用的 AWS 资源以降低成本并消除浪费时,请使用此技能。

自动化清理目标

存储

  • 未挂载的 EBS 卷

  • 旧的 EBS 快照(>90 天)

  • 未完成的分段 S3 上传

  • 开启版本控制存储桶中的旧版本 S3 对象

计算

  • 已停止的 EC2 实例(>30 天)

  • 未使用的 AMI 及其关联快照

  • 未使用的弹性 IP (Elastic IPs)

网络

  • 未使用的弹性负载均衡器 (ELB)

  • 未使用的 NAT 网关

  • 孤立的弹性网络接口 (ENI)

清理脚本

安全清理(先进行模拟运行)

bash
#!/bin/bash

cleanup-unused-ebs.sh

echo "正在查找未挂载的 EBS 卷..."
VOLUMES=$(aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query 'Volumes[*].VolumeId' \
--output text)

for vol in $VOLUMES; do
echo "将删除: $vol"
# 取消注释以实际执行删除:
# aws ec2 delete-volume --volume-id $vol
done

bash
#!/bin/bash

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

echo "快照: $snap_id (创建时间: $start_time, 大小: ${size}GB)"
# 取消注释以执行删除:
# aws ec2 delete-snapshot --snapshot-id $snap_id
done

bash
#!/bin/bash

release-unused-eips.sh

aws ec2 describe-addresses \
--query 'Addresses[?AssociationId==null].[AllocationId,PublicIp]' \
--output text | while read alloc_id public_ip; do

echo "将释放: $public_ip ($alloc_id)"
# 取消注释以执行释放:
# aws ec2 release-address --allocation-id $alloc_id
done

S3 生命周期自动化

bash
# 应用生命周期策略,将旧对象转移到更便宜的存储类
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

成本影响计算器

python
#!/usr/bin/env python3

calculate-savings.py

import boto3
from datetime import datetime, timedelta

ec2 = boto3.client('ec2')

计算 EBS 卷可节省的费用

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 # gp3 为 $0.10/GB-月

print(f"未挂载的 EBS 卷: {len(volumes['Volumes'])}")
print(f"总大小: {total_size} GB")
print(f"每月可节省: ${monthly_cost:.2f}")

计算弹性 IP 可节省的费用

addresses = ec2.describe_addresses() unused = [a for a in addresses['Addresses'] if 'AssociationId' not in a]

eip_cost = len(unused) * 3.65 # $0.005/小时 * 730 小时
print(f"\n未使用的弹性 IP: {len(unused)}")
print(f"每月可节省: ${eip_cost:.2f}")


y 节省金额: ${eip_cost:.2f}")

print(f"\n每月总节省金额: ${monthly_cost + eip_cost:.2f}")
print(f"年度节省金额: ${(monthly_cost + eip_cost) * 12:.2f}")

code
## 自动化清理 Lambda
python
import boto3
from datetime import datetime, timedelta

def lambda_handler(event, context):
ec2 = boto3.client('ec2')

# 删除超过 7 天未挂载的卷
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"已删除卷: {vol['VolumeId']}")
except Exception as e:
print(f"删除 {vol['VolumeId']} 时出错: {e}")

return {
'statusCode': 200,
'body': f'已删除 {deleted} 个卷'
}

code
## 清理工作流

1. 探索阶段(只读)
- 运行所有 describe 命令
- 生成成本影响报告
- 与团队共同评审

2. 验证阶段
- 确认资源确实未被使用
- 检查依赖关系
- 通知资源所有者

3. 执行阶段(先进行模拟运行)
- 以 dry-run 模式运行清理脚本
- 评审拟议的变更
- 执行实际清理

4. 验证阶段
- 确认删除结果
- 监控是否出现问题
- 记录节省金额

安全检查清单

  • [ ] 先以 dry-run 模式运行
  • [ ] 验证资源无依赖关系
  • [ ] 通过资源标签检查所有权
  • [ ] 删除前通知相关利益者
  • [ ] 为关键数据创建快照
  • [ ] 先在非生产环境测试
  • [ ] 准备好回滚方案
  • [ ] 记录所有删除操作

示例提示词 (Prompts)

探索

  • "查找所有未使用的资源并计算潜在节省金额"

  • "为我的 AWS 账户生成一份清理报告"

  • "哪些资源可以安全删除?"

执行

  • "创建一个清理未挂载 EBS 卷的脚本"

  • "删除所有超过 90 天的快照"

  • "释放未使用的弹性 IP (Elastic IPs)"

自动化

  • "为旧快照设置自动化清理"

  • "创建一个用于每周清理的 Lambda 函数"

  • "调度每月资源清理"

与 AWS Organizations 集成

bash

在多个账户中运行清理

for account in $(aws organizations list-accounts \ --query 'Accounts[*].Id' --output text); do echo "正在检查账户: $account" aws ec2 describe-volumes \ --filters Name=status,Values=available \ --profile account-$account done
code
## 监控与告警
bash

为成本异常创建 CloudWatch 警报

aws cloudwatch put-metric-alarm \ --alarm-name high-cost-alert \ --alarm-description "每日成本超过阈值时告警" \ --metric-name EstimatedCharges \ --namespace AWS/Billing \ --statistic Maximum \ --period 86400 \ --evaluation-periods 1 \ --threshold 100 \ --comparison-operator GreaterThanThreshold
code
## 最佳实践
  • 在维护窗口期间调度清理工作
  • 删除前始终创建最终快照
  • 使用资源标签识别清理候选对象
  • 为生产环境实施审批工作流
  • 记录所有清理操作以备审计
  • 设置成本异常检测
  • 每周评审清理结果

风险缓解

中风险操作:

  • 删除未挂载的卷(确保没有计划重新挂载)

  • 删除旧快照(确认无合规性要求)

  • 释放弹性 IP(检查 DNS 记录)

始终坚持:

  • 保持 30 天的备份保留期

  • 对关键资源使用 AWS Backup

  • 测试恢复流程

  • 记录清理决策

Kiro CLI 集成

bash

通过一条命令进行分析并清理

kiro-cli chat "Use aws-cost-cleanup to find and remove unused resources"

生成清理脚本

kiro-cli chat "Create a safe cleanup script for my AWS account"

调度自动化清理

kiro-cli chat "Set up weekly automated cleanup using aws-cost-cleanup" ```

附加资源

局限性

  • 仅在任务明确符合上述范围时使用此技能。
  • 不要将输出结果视为针对特定环境的验证、测试或专家评审的替代方案。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请停止操作并请求澄清。