aws-cost-optimization について
AWS ワークロードを管理するチーム向けの実践的な FinOps スキルです。AWS CLI と Terraform の例を使い、支出分析、リソースの適正化、割引、アラート、不要リソースの整理を扱います。
主な機能
- 01サービスとタグ別の支出分析
- 02コンピュートとストレージの適正化
- 03Savings Plans と RIs の比較
- 04予算とアラートの設定
- 05未使用リソースの特定
活用シーン
- 01AWS 請求額の急増原因を調査
- 02負荷テスト後のリソースサイズ確認
- 03予算とコスト異常アラートの設定
- 04未接続ボリュームと古いスナップショットの整理
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill aws-cost-optimizationインストール後、Claude Code で/aws-cost-optimizationを入力して読み込まれたか確認します。
詳細
AWS コスト最適化
信頼性やパフォーマンスを損なうことなく AWS の支出を削減するため、実践的な FinOps の管理策を適用します。
このスキルを使用するタイミング
- AWS の月額料金が予想外に急増した、または予算のしきい値を超えた場合
- エンジニアリングチームや財務チームとコストレビューを準備する場合
- 負荷テスト後に EC2、RDS、EKS、Lambda のワークロードを適正規模に調整する場合
- Savings Plans、Reserved Instances、オンデマンド料金のいずれを選ぶか検討する場合
- 予算アラートと異常検出を自動化する場合
- 使用していないリソース(未接続の EBS、アイドル状態のロードバランサー、古いスナップショット)を整理する場合
- リージョンや AZ 間のデータ転送料を最適化する場合
前提条件
- AWS CLI v2 がインストールされ、設定済みであること(
aws configure) - IAM 権限:
ce:*、budgets:*、ec2:Describe*、cloudwatch:PutMetricAlarm、s3:PutLifecycleConfiguration - AWS 請求コンソールで Cost Explorer が有効になっていること(データが反映されるまで 24 時間かかります)
- Billing コンソールでコスト配分タグが有効になっていること
コストレビューワークフロー
- すべてのリソースに、チーム、サービス、環境、コストセンターを示すタグを付けます。
- Cost Explorer を有効にし、Cost and Usage Reports(CUR)を有効化して S3 に保存します。
- サービス、アカウント、タグ別に、支出の大きい項目を特定します。
- CloudWatch のメトリクスに基づいて、使用率の低いコンピューティングリソースとストレージのサイズを適正化します。
- 安定したベースライン使用量に対して、コミットメント割引(Savings Plans または RI)を適用します。
- 予算と異常アラートを設定し、KPI ダッシュボードを構築します。
- 毎月レビューして改善を繰り返します。
Cost Explorer CLI コマンド
# Get cost and usage for the last 30 days grouped by service
aws ce get-cost-and-usage \
--time-period Start=2026-02-01,End=2026-03-01 \
--granularity MONTHLY \
--metrics "BlendedCost" "UnblendedCost" "UsageQuantity" \
--group-by Type=DIMENSION,Key=SERVICE
# Get cost forecast for the next 30 days
aws ce get-cost-forecast \
--time-period Start=2026-03-24,End=2026-04-24 \
--metric UNBLENDED_COST \
--granularity MONTHLY
# Get cost grouped by a specific tag (e.g., team)
aws ce get-cost-and-usage \
--time-period Start=2026-02-01,End=2026-03-01 \
--granularity MONTHLY \
--metrics "UnblendedCost" \
--group-by Type=TAG,Key=team
# Get rightsizing recommendations for EC2
aws ce get-rightsizing-recommendation \
--service "AmazonEC2" \
--configuration '{"RecommendationTarget":"SAME_INSTANCE_FAMILY","BenefitsConsidered":true}'
# Get Savings Plans purchase recommendation
aws ce get-savings-plans-purchase-recommendation \
--savings-plans-type COMPUTE_SP \
--term-in-years ONE_YEAR \
--payment-option NO_UPFRONT \
--lookback-period-in-days SIXTY_DAYS
# Get Savings Plans utilization
aws ce get-savings-plans-utilization \
--time-period Start=2026-02-01,End=2026-03-01 \
--granularity MONTHLY
# Get Reserved Instance utilization
aws ce get-reservation-utilization \
--time-period Start=2026-02-01,End=2026-03-01 \
--granularity MONTHLY
予算アラート
# Create a monthly cost budget with email alert at 80% and 100%
aws budgets create-budget \
--account-id 123456789012 \
--budget '{
"BudgetName": "monthly-total",
"BudgetLimit": {"Amount": "5000", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST",
"CostFilters": {},
"CostTypes": {
"IncludeTax": true,
"IncludeSubscription": true,
"UseBlended": false
}
}' \
--notifications-with-subscribers '[
{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80,
"ThresholdType": "PERCENTAGE"
},
"Subscribers": [{"SubscriptionType": "EMAIL", "Address": "[email protected]"}]
},
{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 100,
"ThresholdType": "PERCENTAGE"
},
"Subscribers": [{"SubscriptionType": "EMAIL", "Address": "[email protected]"}]
}
]'
# List all budgets
aws budgets describe-budgets --account-id 123456789012
# Enable Cost Anomaly Detection monitor for all services
aws ce create-anomaly-monitor \
--anomaly-monitor '{
"MonitorName": "all-services",
"MonitorType": "DIMENSIONAL",
"MonitorDimension": "SERVICE"
}'
# Create anomaly subscription (alert when impact > $50)
aws ce create-anomaly-subscription \
--anomaly-subscription '{
"SubscriptionName": "cost-alerts",
"MonitorArnList": ["arn:aws:ce::123456789012:anomalymonitor/monitor-id"],
"Subscribers": [{"Type": "EMAIL", "Address": "[email protected]"}],
"Threshold": 50,
"Frequency": "DAILY"
}'
CloudWatch コストアラーム
# Create alarm for estimated charges exceeding $4000
aws cloudwatch put-metric-alarm \
--alarm-name "billing-alarm-4000" \
--alarm-description "Alert when estimated charges exceed $4000" \
--metric-name EstimatedCharges \
--namespace AWS/Billing \
--statistic Maximum \
--period 21600 \
--threshold 4000 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--dimensions Name=Currency,Value=USD \
--alarm-actions "arn:aws:sns:us-east-1:123456789012:billing-alerts" \
--treat-missing-data notBreaching
未使用リソースの検出と整理
# List unattached EBS volumes (wasted storage spend)
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query "Volumes[].{ID:VolumeId,Size:Size,Created:CreateTime}" \
--output table
# Find old EBS snapshots (older than 90 days)
aws ec2 describe-snapshots \
--owner-ids self \
--query "Snapshots[?StartTime<='2025-12-24'].{ID:SnapshotId,Size:VolumeSize,Date:StartTime}" \
--output table
# List unused Elastic IPs (charged when not associated)
aws ec2 describe-addresses \
--query "Addresses[?AssociationId==null].{IP:PublicIp,AllocId:AllocationId}" \
--output table
# Find idle load balancers (zero healthy targets)
aws elbv2 describe-target-health \
--target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-tg/abc123
# List RDS instances and their utilization
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name CPUUtilization \
--dimensions Name=DBInstanceIdentifier,Value=mydb \
--start-time 2026-03-17T00:00:00Z \
--end-time 2026-03-24T00:00:00Z \
--period 86400 \
--statistics Average
S3 ライフサイクルのコスト最適化
# Apply tiered lifecycle policy to reduce storage costs
aws s3api put-bucket-lifecycle-configuration \
--bucket my-data-bucket \
--lifecycle-configuration '{
"Rules": [
{
"ID": "TierDownOldData",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"Transitions": [
{"Days": 30, "StorageClass": "STANDARD_IA"},
{"Days": 90, "StorageClass": "GLACIER"},
{"Days": 365, "StorageClass": "DEEP_ARCHIVE"}
],
"NoncurrentVersionTransitions": [
{"NoncurrentDays": 30, "StorageClass": "GLACIER"}
],
"NoncurrentVersionExpiration": {"NoncurrentDays": 90}
},
{
"ID": "CleanupIncompleteUploads",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 7}
}
]
}'
Terraform の予算とアラームの例
resource "aws_budgets_budget" "monthly" {
name = "monthly-total"
budget_type = "COST"
limit_amount = "5000"
limit_unit = "USD"
time_unit = "MONTHLY"
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["[email protected]"]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["[email protected]"]
}
}
resource "aws_cloudwatch_metric_alarm" "billing" {
alarm_name = "billing-alarm-4000"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "EstimatedCharges"
namespace = "AWS/Billing"
period = 21600
statistic = "Maximum"
threshold = 4000
alarm_description = "Billing exceeds $4000"
alarm_actions = [aws_sns_topic.billing_alerts.arn]
dimensions = {
Currency = "USD"
}
}
非本番環境のシャットダウンのスケジュール設定
# Stop all dev instances tagged Environment=dev (run via EventBridge + Lambda)
aws ec2 describe-instances \
--filters "Name=tag:Environment,Values=dev" "Name=instance-state-name,Values=running" \
--query "Reservations[].Instances[].InstanceId" \
--output text | xargs -n1 aws ec2 stop-instances --instance-ids
# Scale down dev ECS services to zero at night
aws ecs update-service \
--cluster dev-cluster \
--service dev-api \
--desired-count 0
トラブルシューティング
| 問題 | 原因 | 対処方法 |
|---|---|---|
| Cost Explorer にデータが表示されない | CE が有効になっていない、または有効化から 24 時間未満 | Billing コンソールで有効にし、24 時間待ちます |
| 予算アラートが発火しない | SNS サブスクリプションが確認されていない | メールを確認し、サブスクリプションを承認します |
| 適正化の推奨事項が表示されない | 使用状況データが不足している | 十分なメトリクスが得られるまで 14 日間待ちます |
| Savings Plans の利用率が低い | 購入しすぎた、またはワークロードが変わった | SP のカバレッジを確認して調整します |
| 未接続の EBS が表示されない | 問い合わせたリージョンが違う | すべての有効なリージョンを順に確認します |
| 請求アラームが一度も発火しない | 請求メトリクスは us-east-1 でのみ利用可能 | us-east-1 リージョンにアラームを作成します |
| CUR データが S3 にない | レポートが設定されていない、またはバケットポリシーに誤りがある | Billing コンソールで CUR の設定を確認します |
| タグベースのコスト配分が空 | タグが有効化されていない | Billing でコスト配分タグを有効にします |
関連スキル
- aws-ec2 - EC2 の運用、サイズ調整、Spot インスタンス
- aws-s3 - S3 ストレージクラスとライフサイクル管理
- aws-rds - RDS インスタンスのサイズ調整とリザーブドインスタンス
- aws-lambda - Lambda の料金と同時実行数の調整
- terraform-aws - IaC でコストガードレールをコード化
コメント
Markdown 対応