mcpField
A
aws-cost-cleanup

aws-cost-cleanup

github.com/sickn33クラウド・DevOps48.7k104 回インストール今日更新
リポジトリ

aws-cost-cleanup について

aws-cost-cleanupは、未使用のAWSリソースを見つけて整理する自動化スキルです。クラウドの無駄を調べる運用担当者向けに、ストレージ、コンピューティング、ネットワークを対象とし、削除前の読み取り専用調査、ドライラン、検証を重視します。

主な機能

  1. 01複数種類の未使用AWSリソースを検出
  2. 02コスト影響の見積もりレポートを作成
  3. 03クリーンアップスクリプトとLambdaの例を提示
  4. 04調査、検証、実行、確認の手順を構成
  5. 05削除前の安全確認項目を提示

活用シーン

  1. 01未接続EBSボリュームの整理候補を調査
  2. 02古いスナップショットと未完了S3アップロードを整理
  3. 03停止中のEC2、Elastic IP、ネットワークリソースを確認
  4. 04複数AWSアカウントのリソース調査を計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill aws-cost-cleanup

インストール後、Claude Code で/aws-cost-cleanupを入力して読み込まれたか確認します。

詳細

AWS コストクリーンアップ

未使用の AWS リソースを特定して削除する作業を自動化し、無駄をなくします。

このスキルを使う場面

コストを削減して無駄をなくすために、未使用の AWS リソースを自動的にクリーンアップする必要がある場合にこのスキルを使います。

自動クリーンアップの対象

ストレージ

  • アタッチされていない EBS ボリューム
  • 古い EBS スナップショット(90 日超)
  • 不完全なマルチパート S3 アップロード
  • バージョニングが有効なバケット内の古い S3 バージョン

コンピューティング

  • 停止中の EC2 インスタンス(30 日超)
  • 未使用の AMI と関連するスナップショット
  • 未使用の Elastic IP

ネットワーキング

  • 未使用の Elastic Load Balancer
  • 未使用の NAT Gateway
  • 孤立した ENI

クリーンアップスクリプト

安全なクリーンアップ(まずはドライラン)
#!/bin/bash
# cleanup-unused-ebs.sh

echo "Finding unattached EBS volumes..."
VOLUMES=$(aws ec2 describe-volumes \
  --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
#!/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 "Snapshot: $snap_id (Created: $start_time, Size: ${size}GB)"
  # Uncomment to delete:
  # aws ec2 delete-snapshot --snapshot-id $snap_id
done
#!/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 "Would release: $public_ip ($alloc_id)"
  # Uncomment to release:
  # aws ec2 release-address --allocation-id $alloc_id
done
S3 ライフサイクルの自動化
# Prepare a lifecycle proposal. This replaces bucket lifecycle configuration;
# retrieve/merge existing rules and scope the prefix before any authorized apply.
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

# After explicit review only, apply the merged policy to the confirmed bucket.

コスト削減効果の計算

#!/usr/bin/env python3
# calculate-savings.py

import boto3
from datetime import datetime, timedelta

ec2 = boto3.client('ec2')

# 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  # illustrative input, not a verified gp3 rate

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
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}")

自動クリーンアップ Lambda

import boto3
from datetime import datetime, timedelta

def lambda_handler(event, context):
    ec2 = boto3.client('ec2')
    
    # Discover candidates only; creation age is not detachment age.
    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:
                print(f"Candidate only (not deleted): {vol['VolumeId']}")
            except Exception as e:
                print(f"Error deleting {vol['VolumeId']}: {e}")
    
    return {
        'statusCode': 200,
        'body': 'Dry run only; no volumes deleted'
    }

クリーンアップのワークフロー

  1. 検出フェーズ(読み取り専用)

    • すべての describe コマンドを実行します
    • コスト削減効果のレポートを生成します
    • チームで内容を確認します
  2. 検証フェーズ

    • リソースが本当に未使用であることを確認します
    • 依存関係を確認します
    • リソースの所有者に通知します
  3. 実行フェーズ(まずはドライラン)

    • ドライランでクリーンアップスクリプトを実行します
    • 予定されている変更を確認します
    • 実際にクリーンアップを実行します
  4. 確認フェーズ

    • 削除を確認します
    • 問題がないか監視します
    • 削減額を記録します

安全性チェックリスト

  • まずドライランモードで実行します
  • リソースに依存関係がないことを確認します
  • リソースタグで所有者を確認します
  • 削除前に関係者へ通知します
  • 重要なデータのスナップショットを作成します
  • まず非本番環境でテストします
  • ロールバック計画を用意します
  • すべての削除を記録します

プロンプトの例

検出

  • 「未使用のリソースをすべて見つけて、削減できる金額を計算してください」
  • 「AWS アカウントのクリーンアップレポートを生成してください」
  • 「安全に削除できるリソースはどれですか?」

実行

  • 「アタッチされていない EBS ボリュームをクリーンアップするスクリプトを作成してください」
  • 「90 日より古いスナップショットをすべて削除してください」
  • 「未使用の Elastic IP を解放してください」

自動化

  • 「古いスナップショットの自動クリーンアップを設定してください」
  • 「週次クリーンアップ用の Lambda 関数を作成してください」
  • 「リソースのクリーンアップを毎月実行するようスケジュールしてください」

AWS Organizations との統合

# Run cleanup across multiple accounts
for account in $(aws organizations list-accounts \
  --query 'Accounts[*].Id' --output text); do
  
  echo "Checking account: $account"
  aws ec2 describe-volumes \
    --filters Name=status,Values=available \
    --profile account-$account
done

モニタリングとアラート

# 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

ベストプラクティス

  • メンテナンス時間中にクリーンアップをスケジュールします
  • 削除前に必ず最終スナップショットを作成します
  • リソースタグを使ってクリーンアップ候補を特定します
  • 本番環境では承認ワークフローを導入します
  • 監査用にすべてのクリーンアップ操作を記録します
  • コスト異常検出を設定します
  • クリーンアップの結果を毎週確認します

リスクの軽減

中リスクの操作:

  • アタッチされていないボリュームの削除(再アタッチの予定がないことを確認します)
  • 古いスナップショットの削除(コンプライアンス要件がないことを確認します)
  • Elastic IP の解放(DNS レコードを確認します)

必ず実施すること:

  • 30 日間のバックアップ保持を維持します
  • 重要なリソースには AWS Backup を使用します
  • 復元手順をテストします
  • クリーンアップの判断を記録します

Kiro CLI との統合

# Analyze and cleanup in one command
kiro-cli chat "Use aws-cost-cleanup to find and remove unused resources"

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

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

追加リソース

制限事項

  • タスクが上記の説明にある対象範囲に明確に合致する場合にのみ、このスキルを使用してください。
  • 出力を、環境固有の検証、テスト、または専門家によるレビューの代替として扱わないでください。
  • 必要な入力、権限、安全上の境界、または成功基準が不足している場合は、作業を中断して確認してください。

未アタッチ、停止中、または古いリソースであっても、復旧に必要な資産である可能性があります。削除する前に、アカウント/リージョン、所有者、候補 ID の明示、依存関係の確認、保持要件、およびテスト済みのバックアップ/復元計画を確認してください。作成時刻から、ボリュームが未使用になった時期を判断することはできません。デフォルトではドライランを維持してください。個別に承認された実行では、状態/タグと対象範囲を再確認し、IAM のスコープを限定してください。対象リージョン全体でページネーションを使用して検出し、現在のリージョン/タイプ/IOPS/スループット/IPv4 の料金を使用するとともに、見積もり上の削減コストと実際に請求額から削減された金額を区別してください。GNU date -d は macOS では移植性がありません。

コメント