- 1 1. なぜコスト最適化か — AWS本番運用6軸目 + 既存5シリーズからの架橋
- 2 2. AWS Cost管理3本柱整理 — 可視化 / 予測 / 最適化 + AWSサービスマップ
- 3 3. Cost Explorer設計実践 (山場1) — CUR / Granularity / Filters / Group By / Forecast
- 4 4. Budgets実践 — Budget types / Threshold / SNS通知 / EventBridge自動対応
- 5 5. Compute Optimizer実践 — Recommendations / EC2 / EBS / Lambda / Auto Scaling Group
- 6 6. 詰まりポイント7選 図解
- 6.1 6-1. Cost Allocation Tags 設計ミス(大文字/小文字不統一 / Key設計不足)
- 6.2 6-2. Cross-Account 集約で管理アカウントのコストが不明(CUR 設定漏れ)
- 6.3 6-3. Reserved Instance 購入タイミング失敗(Expiry 前のリニューアル漏れ)
- 6.4 6-4. Savings Plans 選定ミス(Compute SP vs EC2 Instance SP)
- 6.5 6-5. Spot Instance 中断への備えなし(Termination Notice 未対応)
- 6.6 6-6. Data Transfer 隠れコスト(NAT Gateway / ALB / Cross-AZ)
- 6.7 6-7. Tag-based Cost Report の集計漏れ(Untagged リソース問題)
- 7 7. アンチパターン→正解パターン変換演習 (Terraform + CUR yaml + Lambda 3形式)
- 8 8. まとめ + Vol2予告 + 落とし穴10選 + 全シリーズクロスリンク + AWS本番運用6軸完結宣言
1. なぜコスト最適化か — AWS本番運用6軸目 + 既存5シリーズからの架橋
- IAM入門シリーズ: Vol1 ポリシー設計 / Vol2 マルチアカウント / Vol3 棚卸自動化 / Vol4 STS
- EKS本番運用シリーズ: Vol1 Cluster設計 / Vol2 観測可能性 / Vol3 GitOps
- 復旧・運用編シリーズ: Vol1 DR / Vol2 Chaos / Vol3 対応自動化 / Vol4 マルチリージョン
- AIシリーズ: Vol1 Bedrock Agents
- セキュリティ本格運用シリーズ: Vol1 Security Hub × GuardDuty × Audit Manager / Vol2 GuardDuty × Security Hub × Detective 統合運用
1-1. なぜAWSコスト最適化が今重要か — 3つのリスクと放置ペナルティ
IAM・EKS・復旧・AI・セキュリティ と積み上げてきた AWS本番運用の5軸は、インフラの機能面を網羅しています。しかしどれだけ堅牢な本番環境を構築しても、コストが制御されていなければビジネスの継続可能性を損なうリスクがあります。AWS の課金モデルは「使った分だけ払う」という柔軟性を持つ反面、可視化・予測・最適化を怠ると月次請求が予測不能になります。6軸目のコスト最適化は、構築した本番基盤を「持続可能」にするための軸です。
「コスト最適化はFinOpsチームの仕事」と考えているエンジニアが多いですが、実際にはアーキテクチャ設計の段階でコストが決まるケースがほとんどです。インスタンスタイプの選定・マルチリージョン構成の採否・データ転送パターン・ログ保持期間――これらはすべて設計フェーズのエンジニア判断がコストに直結します。本シリーズでは「コストを意識した設計者」になることを目標とします。
リスク1: 月次請求サプライズ
AWSの請求は毎月1日に確定しますが、リソースの使用量は日次・時次でリアルタイムに積み上がっています。開発・検証用に立ち上げたEC2インスタンスの停止忘れ、大量データの誤ったS3 Glacier Instant Retrieval への格納、EKS ノードグループの過剰スケール設定などが原因で、予算の数倍の請求が届くことがあります。Cost Anomaly Detection を設定していなければ、請求確定まで異常に気づけません。
【月次請求サプライズの典型パターン】
m5.2xlarge (8vCPU/32GB) 放置例:
・オンデマンド: $0.384/h × 720h = $276/月 (約4.1万円)
・RI未適用: 1年分 = 約49万円の超過コスト
EKS ノード過剰スケール例:
・Worker node 10台 (m5.xlarge) × $0.192/h × 720h = $1,382/月
・適正規模 5台なら $691/月 → 差額 $691/月 = 年間 $8,292
RDS Multi-AZ 開発環境放置例:
・db.r5.2xlarge Multi-AZ: $0.96/h × 720h = $691/月
・検証終了後の削除忘れ → 年間 $8,292 の無駄
リスク2: 無駄リソースの蓄積
クラウド環境では「作っては放置」が積み重なります。未使用のEBSボリューム・削除したEC2インスタンスに残ったスナップショット・誰も使わなくなったElastic IP・古いAMI・アイドル状態のNATゲートウェイなど、個々の金額は小さくても積み上がると数万円〜数十万円の年間無駄コストになります。Compute Optimizer と AWS Trusted Advisor が定期的にこれらを検出しますが、自動的には削除されないため能動的な最適化が必要です。
【無駄リソース蓄積のよくあるパターン】
リソース種別 月額目安 年間累積
──────────────────────────────────────────
未使用 EBS (100GB) $10/月 $120
アイドル Elastic IP$3.6/月$43
古い EBS スナップショット (1TB) $50/月 $600
停止中 NAT Gateway $32/月 $384
未使用 ALB$16/月 $192
──────────────────────────────────────────
合計 (小規模環境)$111.6/月 $1,339/年
リスク3: RI/Savings Plans 期限切れによるコスト増
Reserved Instances (RI) や Savings Plans は 1〜3 年の契約で最大 72% のコスト削減を実現しますが、期限切れを見逃すとオンデマンド価格に自動復帰します。本番環境で年単位で安定稼働するEC2やRDS・Fargate は、RI/Savings Plans を適用することが前提の設計であることが多く、期限切れによる料金増加は予算管理の大きなリスクです。Budgets のアラートと Cost Explorer の RI Coverage レポートを組み合わせた「更新管理」が必要です。AWS Organizations 環境では RI の共有設定 (linked account への適用) も更新漏れの原因になります。RI 期限の 90 日前にアラートを設定し、計画的に更新または Savings Plans への切り替えを検討することが、コスト管理成熟度の指標となります。
1-2. コスト最適化3ステージと本記事の位置付け
AWSコスト最適化は「認知 → 改善 → 持続」の3ステージで体系化できます。多くの組織がいきなり最適化 (Stage3) から着手して失敗しますが、可視化 (Stage1) と予測 (Stage2) なしに最適化は継続しません。
【コスト最適化3ステージ】
Stage1: 可視化 (Observe)
─────────────────────────────────────────
・何に / どれだけ / どのサービスで使っているかを把握
・Cost Explorer: 日次/月次/サービス別/リージョン別コスト分析
・CUR (Cost and Usage Report): 詳細使用量データをS3に出力
・Cost Allocation Tags: チーム別・プロジェクト別コスト配賦
Stage2: 予測 (Predict)
─────────────────────────────────────────
・来月のコストを把握・アラートで異常を早期検知
・Budgets: 月次予算設定 + SNS/メール通知
・Forecasting: ML予測 (90日先まで自動計算)
・Anomaly Detection: 異常な支出パターンをML検知
Stage3: 最適化 (Optimize)
─────────────────────────────────────────
・リソースのサイズ・タイプ・購入形態を最適化
・Compute Optimizer: EC2/EBS/Lambda/ECS 適正サイジング推奨
・RI / Savings Plans: コミットメント割引 (最大72%削減)
・Spot Instance: 中断許容ワークロードを大幅削減
本記事では3つのサービスをステージに対応させて解説します。
| ステージ | 代表サービス | 本記事での解説章 |
|---|---|---|
| Stage1 可視化 | Cost Explorer / CUR / Tags | §3 Cost Explorer 実践 |
| Stage2 予測 | Budgets / Forecasting / Anomaly Detection | §4 Budgets 実践 |
| Stage3 最適化 | Compute Optimizer / RI / Savings Plans | §5 Compute Optimizer 実践 |
3ステージを1記事で網羅的に解説することで、「どのサービスが何のために存在するか」の全体像を把握してから各実装に進めます。コスト最適化の詰まりポイント (§6) と Terraform IaC 化 (§7) も合わせて習得できます。
3サービスを統合解説する意義
Cost Explorer・Budgets・Compute Optimizer は単独で使うよりも、3サービスを連携させることで効果が倍増します。例えば「Cost Explorer で急増を検知 → Budgets アラートで通知 → Compute Optimizer で原因リソースを特定 → 推奨に従い最適化」というフローが自然に成立します。さらに Anomaly Detection の異常スコアと Budgets の閾値を組み合わせると、請求確定前の早期対処が可能になり、月次コストの予測精度が大幅に向上します。本記事はこの3サービス連携の全体フローを習得することを主目的としています。
1-3. 全13巻読了済エンジニアへ — 6軸完結への昇格
IAM・EKS・復旧・AI・セキュリティの5軸で積み上げた知識は、コスト最適化に直結します。各シリーズとコスト管理の接点を整理します。
IAMシリーズ (Vol1-4) で学んだ最小権限設計 → Cost Allocation Tags と Organizations SCP でチーム別コスト配賦を制御。IAM Vol2 のマルチアカウント設計と Cost Explorer の Account 別分析を組み合わせると、どのアカウントがコストを消費しているかが一画面で把握できます。
EKSシリーズ (Vol1-3) で学んだクラスター設計 → Compute Optimizer の EKS ノード推奨でワーカーノードの適正サイジングを実現。EKS Vol1 で設計した Auto Scaling と Compute Optimizer の推奨を組み合わせると、ピーク時コストを最小化しながら可用性を維持できます。Karpenter との連携で Spot Instance 活用も深まります。
復旧シリーズ (Vol1-4) で学んだ DR 設計 → Cross-Region DR のコスト試算を Cost Explorer で可視化。復旧 Vol1 で設計した S3 Cross-Region Replication や RDS クロスリージョンバックアップのコストを定量的に把握し、RPO/RTO とコストのトレードオフを意思決定できます。
AIシリーズ (Vol1) で学んだ Bedrock Agents → Bedrock モデル呼び出しコストを Cost Explorer で追跡。AI Vol1 で構築した Bedrock 本番基盤では、Claude モデルの input/output token 数がコストに直結するため、Usage レポートと Budgets のアラートが必須です。
セキュリティ本格運用 (Vol1) で学んだ Security Hub / GuardDuty → セキュリティサービスのコスト管理。GuardDuty は分析 GB 単価 + 追加保護機能ごとに課金され、Findings 件数が多い環境ではコストが急増します。Cost Explorer でセキュリティサービスのコストを分離して追跡する設計が必要です。
【AWS本番運用 6軸 全体像】
IAM設計──→ 最小権限・マルチアカウント ──→ コスト配賦・SCP制御
EKS設計──→ クラスター・Auto Scaling ──→ Compute Optimizer 適正化
復旧設計──→ DR・クロスリージョン──→ コスト試算・最適な RPO/RTO
AI設計 ──→ Bedrock 本番基盤──→ Token コスト追跡
セキュリティ ──→ Security Hub・GuardDuty ──→ セキュリティコスト管理
コスト最適化 ──→ Cost Explorer・Budgets ──→ 6軸すべてを持続可能に
Compute Optimizer
↓
AWS本番運用 6軸完結
AWS本番運用 6軸 比較表
| 軸 | シリーズ | 核心サービス | コスト最適化との連携 |
|---|---|---|---|
| IAM | IAM入門4巻 | IAM / STS | Cost Allocation Tags / SCP コスト制御 |
| EKS | EKS本番運用3巻 | EKS / ALB / ArgoCD | Compute Optimizer EKS ノード最適化 |
| 復旧 | 復旧・運用編4巻 | AWS Backup / FIS | DR コスト試算 / クロスリージョン最適化 |
| AI | AIシリーズ | Bedrock Agents | Bedrock model invocation コスト追跡 |
| セキュリティ | セキュリティ本格運用 | Security Hub / GuardDuty | セキュリティサービスコスト分析 |
| コスト最適化 | 本シリーズ | Cost Explorer / Budgets / Compute Optimizer | ← いまここ |
本シリーズで AWS本番運用の 6軸が完結します。IAMポリシー設計から始まり、EKS本番クラスタ・復旧自動化・Bedrock AI基盤・セキュリティ統合監視・そしてコスト最適化まで、AWSの本番運用に必要なすべての知識が一本の線でつながります。本記事を読了し、コスト最適化を本番環境に組み込むことが6軸完結の最終ステップです。
前の13巻でインフラの「機能」を構築しました。本巻ではその「持続可能性」を確保します。堅牢な本番環境も、コストが青天井であれば経営判断でクラウド活用自体が見直されるリスクがあります。コスト最適化はエンジニアの「コスト意識」ではなく、本番基盤の設計要件です。§2以降で Cost Explorer・Budgets・Compute Optimizer の実装に入る前に、この認識を共有することが§1の目的です。
コスト最適化は一度実施して終わりではありません。
ワークロードが進化し、新機能が追加されるたびに最適化の余地が生まれます。
本記事で習得する3サービスのサイクル (可視化 → 予測 → 最適化 → 再可視化) を継続的に回すことが、長期的な AWS 活用コストの低減につながります。
2. AWS Cost管理3本柱整理 — 可視化 / 予測 / 最適化 + AWSサービスマップ
AWS のコスト管理は「可視化 / 予測 / 最適化」の3本柱で体系化できます。可視化なき最適化は効果測定ができず、予測なき可視化は後追いの対応しかできません。この章では3本柱の定義・AWSサービスとの対応関係・実践アーキテクチャ・成熟度モデルを整理します。

2-1. コスト管理3本柱の全体像
【AWS コスト管理3本柱 関係図】
┌─────────────────────────────────────────────────────┐
│ 柱1: 可視化 (Visibility) │
│ CUR (S3) → Athena/QuickSight → Cost Explorer │
│ Cost Allocation Tags → サービス/チーム別コスト分解│
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 柱2: 予測 (Forecasting) │
│ Budgets (閾値アラート) → SNS/EventBridge → Lambda│
│ Anomaly Detection (ML異常検知) → 急増早期警戒 │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 柱3: 最適化 (Optimization) │
│ Compute Optimizer (ML推奨) → EC2/EBS/Lambda/ASG │
│ RI / Savings Plans / Spot → 購買戦略最適化 │
│ Trusted Advisor → 未使用リソース発見 │
└─────────────────────────────────────────────────────┘
| 柱 | 役割 | 代表 AWS サービス |
|---|---|---|
| 可視化 | 現在のコスト構造を正確に把握する | Cost Explorer / CUR / Cost Allocation Tags |
| 予測 | コスト急増を早期検知・通知する | Budgets / Anomaly Detection / Forecast API |
| 最適化 | リソース・購買戦略を改善してコストを削減する | Compute Optimizer / RI / Savings Plans / Spot / Trusted Advisor |
3本柱の中で「可視化」が最も先に整備すべき基盤です。Cost Allocation Tags なしには「どのサービス・チームが何に費やしているか」が判明せず、最適化の効果測定もできません。新規 AWS アカウントで最初にやるべきことは Cost Allocation Tags の設計と CUR の S3 出力設定です。
コスト管理の成長段階を把握することで、現状のギャップと次のアクションが明確になります。
【コスト管理の成長段階 (Cost Awareness Journey)】
Stage 1: 気づき — 「先月いくらかかった?」
↓ AWS 請求コンソール / Cost Explorer で確認開始
Stage 2: 可視化 — 「何に・誰が・どこで使っている?」
↓ Cost Allocation Tags 設計 → CUR + Athena + QuickSight
Stage 3: 予測 — 「来月いくらになりそう? 急増はないか?」
↓ Budgets アラート → Anomaly Detection → Forecast API
Stage 4: 最適化 — 「削減できるリソースはどこ?」
↓ Compute Optimizer → RI/Savings Plans 購入 → Spot 活用
Stage 5: 自動化 — 「人手なしでコストを制御したい」
↓ Budgets Actions → Lambda → 自動停止/スケールダウン
多くの企業が Stage 1〜2 に留まっています。本記事では Stage 3〜4 の実装を中心に解説します。
2-2. 各柱の AWS サービス詳細マップ
| サービス | 担当柱 | 主な機能 | 有効化優先度 |
|---|---|---|---|
| Cost & Usage Report (CUR) | 可視化 | 時間単位・リソース単位の詳細コストデータを S3 に出力 | ★ 最優先 |
| Cost Explorer | 可視化 | 過去 13 ヶ月のコスト・使用量をグラフ化・フィルタ分析 | ★ 最優先 |
| Cost Allocation Tags | 可視化 | チーム/プロジェクト/環境別コスト分解の前提条件 | ★ 最優先 |
| AWS Budgets | 予測 | コスト/使用量/RI/SP の4タイプで閾値アラート + 自動アクション | ★ 高 |
| Cost Anomaly Detection | 予測 | ML でコスト急増パターンを自動検知・SNS アラート | ★ 高 |
| Compute Optimizer | 最適化 | ML 分析で EC2/EBS/Lambda/ASG の過剰プロビジョニングを検出 | ○ 中 |
| Trusted Advisor | 最適化 | 未使用 EIP/未アタッチ EBS/アイドル EC2 等の節約チェック | ○ 中 |
| Savings Plans | 最適化 | コンピューティング使用量を事前コミットして最大 66% 削減 | ○ 中 |
Cost Explorer — リアルタイム可視化の中核
Cost Explorer は過去 13 ヶ月のコストデータをサービス・アカウント・リージョン・タグで任意に絞り込める分析ツールです。Granularity を Monthly/Daily/Hourly と切り替えることで、月次予算管理から時間単位のスパイク分析まで対応します。
CUR (Cost & Usage Report) は Cost Explorer の元データとなる CSV/Parquet ファイルを S3 に出力します。Athena + QuickSight と連携することで、タグ別・リソース単位の詳細なコストダッシュボードを構築できます。
Terraform で CUR と Budgets を一括設定する例:
# Cost & Usage Report の設定
resource "aws_cur_report_definition" "main" {
report_name = "production-cur"
time_unit= "HOURLY"
format= "Parquet"
compression = "Parquet"
additional_schema_elements = ["RESOURCES"]
s3_bucket= aws_s3_bucket.cur.id
s3_prefix= "cur/"
s3_region= "ap-northeast-1"
additional_artifacts = ["ATHENA"]
report_versioning = "OVERWRITE_REPORT"
}
# 月次コスト予算アラート ($1,000 超過で通知)
resource "aws_budgets_budget" "monthly_cost" {
name = "monthly-cost-budget"
budget_type = "COST"
limit_amount= "1000"
limit_unit = "USD"
time_unit= "MONTHLY"
time_period_start = "2024-01-01_00:00"
notification {
comparison_operator = "GREATER_THAN"
threshold= 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.cost_alert.arn]
}
}
Budgets — 4タイプのコスト予算管理
| Budget タイプ | 目的 | 例 |
|---|---|---|
| Cost Budget | 月次コスト上限 | 「月間 $1,000 を超えたら通知」 |
| Usage Budget | サービス使用量上限 | 「EC2 t3.medium を 100 時間以上使ったら通知」 |
| RI Utilization Budget | RI の使用率下限 | 「RI 使用率が 80% を下回ったら通知」 |
| Savings Plans Coverage Budget | SP のカバレッジ下限 | 「SP カバレッジが 70% を下回ったら通知」 |
Budget Actions を設定すると、閾値超過時に IAM ポリシーのアタッチ/デタッチや EC2/RDS の停止を自動実行できます。開発環境の野放しコスト増加を防ぐ自動停止パイプラインに有効です。
Compute Optimizer — ML によるリソース最適化推奨
Compute Optimizer は過去 14 日間の CloudWatch メトリクスを ML で解析し、以下のリソースに対して「過剰プロビジョニング」「過小プロビジョニング」「最適化済み」のいずれかを判定します。
| 対象リソース | 推奨内容の例 |
|---|---|
| EC2 インスタンス | m5.xlarge → m5.large に縮小して月 $50 削減 |
| EBS ボリューム | gp2 → gp3 に変更して 20% コスト削減 |
| Lambda 関数 | メモリ 512MB → 256MB で実行時間が短縮しコスト最適 |
| Auto Scaling Group | 最大キャパシティの過剰設定を検出 |
Savings Plans と Reserved Instances の使い分け
| 購買戦略 | 柔軟性 | 割引率 | 対象 |
|---|---|---|---|
| On-Demand | 最高 | 0% (基準) | スパイク・不定期ワークロード |
| Spot Instance | 中 (中断あり) | 最大 90% 割引 | バッチ処理・CI/CD |
| Compute Savings Plans | 高 (ファミリー問わず) | 最大 66% 割引 | 安定した汎用ワークロード |
| EC2 Instance Savings Plans | 中 (ファミリー固定) | 最大 72% 割引 | 特定ファミリーを長期使用 |
| Reserved Instance (RI) | 低 (インスタンスタイプ固定) | 最大 75% 割引 | DB (RDS/ElastiCache) |
購買戦略の選定は Compute Optimizer と Cost Explorer の RI/SP 推奨機能を使います。「過去 7〜30 日の使用パターン」を分析し、ROI が最大になる購入量と期間 (1年/3年) を推奨してくれます。RI 使用率が 80% を超えている場合は追加購入を検討し、60% を下回っている場合は RI Marketplace での売却を検討します。
2-3. 3本柱を組み合わせる実践アーキテクチャ
【月次コスト管理サイクル】
Week 1: 可視化レビュー
Cost Explorer で前月比較 → CUR + Athena で異常リソース特定
→ Cost Allocation Tags でチーム別内訳確認
Week 2: 予測アラート確認
Budgets アラート履歴レビュー → Anomaly Detection 検知一覧
→ 次月予算超過リスクの評価
Week 3: 最適化実施
Compute Optimizer 推奨確認 → Trusted Advisor チェック
→ RI/Savings Plans 購入判断 (使用率 > 80% が目安)
Week 4: 報告・次月計画
チーム別コストレポート → KPI 更新 → 翌月予算承認
Organizations を使ったマルチアカウント環境では、管理アカウントで CUR を一元収集し、メンバーアカウントのコストを単一の S3 バケットに集約します。
| 成熟度レベル | 状態 | 導入済みサービス |
|---|---|---|
| Level 1 (基礎) | コストが不明・アラートなし | Cost Explorer のみ |
| Level 2 (管理) | 月次アラートあり・タグ整備中 | + Budgets + Cost Allocation Tags |
| Level 3 (最適化) | 自動推奨適用・RI/SP 戦略あり | + Compute Optimizer + CUR + Anomaly Detection |
本記事の目標は Level 3 の実現です。§3 (Cost Explorer 実践)・§4 (Budgets)・§5 (Compute Optimizer) で各柱を段階的に構築します。
コスト管理ツールのコスト自体も考慮します。
| サービス | 課金モデル | 月額目安 |
|---|---|---|
| Cost Explorer | リクエスト単価 (API 呼び出し $0.01/件) | $1〜$10 |
| CUR | S3 ストレージ費用のみ | $1〜$5 |
| Budgets | 最初の2予算は無料、3つ目以降 $0.02/日 | $0〜$5 |
| Compute Optimizer | 無料 (EC2/EBS/Lambda/ASG) | $0 |
| Trusted Advisor | Business/Enterprise サポートプランで全チェック有効 | プラン費用に含む |
コスト管理ツール自体は非常に安価です。最初の導入コストを気にせずに全サービスを有効化することを推奨します。
- 可視化なき最適化は暗闇の手探り: まず Cost Allocation Tags を設計し CUR を S3 に流す。タグ設計なしに始めると、後から全リソースへの付与が困難になる
- 予測なき可視化は後追い対応: Budgets + Anomaly Detection でコスト急増を事前検知する。月末の請求書を見て驚くのではなく、週次アラートで先手を打つ
- 最適化は継続サイクル: Compute Optimizer の推奨は月次レビューを習慣化する。一度の最適化で終わりではなく、使用パターンの変化に合わせて継続的に見直す
3. Cost Explorer設計実践 (山場1) — CUR / Granularity / Filters / Group By / Forecast
3-1. Cost & Usage Report (CUR) — S3 配信 + Athena / QuickSight 連携
Cost & Usage Report (CUR) は AWS の請求データを最も詳細に記録するレポートです。サービス別・リソース別・タグ別のコストを Parquet 形式で S3 に自動配信し、Athena + QuickSight でアドホッククエリと可視化を実現します。
CUR S3 配信設定 — Terraform
resource "aws_s3_bucket" "cur" {
bucket = "${local.account_id}-cur-reports"
}
resource "aws_s3_bucket_policy" "cur" {
bucket = aws_s3_bucket.cur.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowCURWrite"
Effect = "Allow"
Principal = {
Service = "billingreports.amazonaws.com"
}
Action= ["s3:GetBucketAcl", "s3:GetBucketPolicy"]
Resource = aws_s3_bucket.cur.arn
},
{
Sid = "AllowCURPutObject"
Effect = "Allow"
Principal = {
Service = "billingreports.amazonaws.com"
}
Action= "s3:PutObject"
Resource = "${aws_s3_bucket.cur.arn}/*"
}
]
})
}
resource "aws_cur_report_definition" "main" {
report_name = "daily-cost-report"
time_unit= "DAILY"
format= "Parquet"
compression = "Parquet"
additional_schema_elements = ["RESOURCES"]
s3_bucket= aws_s3_bucket.cur.id
s3_region= "us-east-1"
s3_prefix= "cur"
report_versioning = "OVERWRITE_REPORT"
additional_artifacts = ["ATHENA"]
}
additional_artifacts = ["ATHENA"] を指定すると、CUR が Athena 用の Parquet ファイルと Glue テーブル定義を自動生成します。s3_region は CUR の制約により us-east-1 固定です。
Glue Crawler + Athena クエリ設定
resource "aws_glue_crawler" "cur" {
name = "cur-crawler"
role = aws_iam_role.glue_crawler.arn
database_name = "cur_database"
s3_target {
path = "s3://${aws_s3_bucket.cur.id}/cur/daily-cost-report/"
}
schedule = "cron(0 6 * * ? *)"
}
Glue Crawler を毎朝 6 時に実行することで、前日の CUR データが Athena から照会できるようになります。
# Athena でサービス別日次コストを集計するクエリ例
athena_query='
SELECT
line_item_product_code,
SUM(line_item_blended_cost) AS total_cost
FROM "cur_database"."daily_cost_report"
WHERE year = '''2026''' AND month = '''05'''
GROUP BY line_item_product_code
ORDER BY total_cost DESC
LIMIT 20;
'
aws athena start-query-execution--query-string "$athena_query"--query-execution-context Database=cur_database--result-configuration OutputLocation=s3://my-athena-results/--region us-east-1
3-2. Cost Explorer Granularity / Filters / Group By 実践
Cost Explorer ではGranularity(集計粒度)・Filters(フィルタ条件)・Group By(グループ化軸)の3要素を組み合わせてコスト分析します。

| 設定項目 | 選択肢 | 用途 |
|---|---|---|
| Granularity | HOURLY | 短期スパイク検知 / 時間別トレンド |
| Granularity | DAILY | 日次コスト推移 / 異常検知 |
| Granularity | MONTHLY | 月次予算管理 / 前月比 |
| Filters | LinkedAccount | アカウント別コスト抽出 |
| Filters | Service | EC2 / RDS / S3 など個別サービス |
| Filters | UsageType | データ転送 / リクエスト数など |
| Filters | TagKey+TagValue | Cost Allocation Tags でプロジェクト別集計 |
| Group By | SERVICE | サービス別コスト比較 |
| Group By | LINKED_ACCOUNT | アカウント別コスト可視化 |
| Group By | TAG (CostCenter) | コストセンター別配賦 |
Python boto3 API 呼び出し例
import boto3
from datetime import datetime, timedelta
ce = boto3.client('ce', region_name='us-east-1')
response = ce.get_cost_and_usage(
TimePeriod={
'Start': (datetime.today() - timedelta(days=30)).strftime('%Y-%m-%d'),
'End':datetime.today().strftime('%Y-%m-%d'),
},
Granularity='DAILY',
Filter={
'Dimensions': {
'Key': 'LINKED_ACCOUNT',
'Values': ['123456789012', '987654321098']
}
},
GroupBy=[
{'Type': 'DIMENSION', 'Key': 'SERVICE'},
{'Type': 'TAG', 'Key': 'CostCenter'}
],
Metrics=['BlendedCost', 'UnblendedCost']
)
for result in response['ResultsByTime']:
for group in result['Groups']:
print(f"{result['TimePeriod']['Start']} | {group['Keys']} | {group['Metrics']['BlendedCost']['Amount']}")
GROUP BY に TAG を使う場合は事前に Cost Allocation Tags を AWS 管理コンソール または Terraform で有効化する必要があります。タグを有効化していない状態で CUR を取得しても Tag 列は空になります。
Cost Allocation Tags 有効化 (AWS CLI)
# コスト配分タグを有効化
aws ce create-cost-category-definition--name "CostCenter"--rule-version "CostCategoryExpression.v1"--rules '[{"Value":"Engineering","Rule":{"Tags":{"Key":"CostCenter","Values":["engineering"]}}}]'--region us-east-1
# 既存タグ一覧確認
aws ce list-cost-allocation-tags--status Active--region us-east-1--query 'CostAllocationTags[].TagKey'
Cost Allocation Tags は有効化した翌日以降のデータから Tag 列が埋まります。過去分は遡及されないため、プロジェクト立ち上げ時に早期に設定することが重要です。推奨タグキーは Environment / CostCenter / Project / Team の4種類を最低限定義します。
3-3. Cross-Account 集約 + Organizations 連携
Organizations の管理アカウントで CUR を設定すると、全メンバーアカウントのコストが単一の S3 バケットに集約されます。IAM Multi-Account設計 で構成した Organizations 構造を Cost Explorer の Cross-Account 集約にそのまま活用します。
| 集約レベル | 設定場所 | 取得範囲 |
|---|---|---|
| 管理アカウント CUR | Organizations 管理アカウント | 全メンバーアカウント込み |
| メンバーアカウント CUR | 個別アカウント | そのアカウントのみ |
| Cost Explorer コンソール | 管理アカウントでログイン | Consolidated Billing 全体 |
管理アカウントの CUR は line_item_usage_account_id 列でメンバーアカウントを識別できます。Athena クエリで GROUP BY line_item_usage_account_id を指定することでアカウント別コスト配賦レポートが作成できます。
3-4. Forecast と Anomaly Detection
Forecast API — 30 / 60 / 90 日予測
# Cost Anomaly Detection Monitor
resource "aws_ce_anomaly_monitor" "linked_account" {
name= "linked-account-anomaly-monitor"
monitor_type = "DIMENSIONAL"
monitor_dimension = "SERVICE"
}
resource "aws_ce_anomaly_subscription" "daily_alert" {
name= "daily-anomaly-alert"
frequency = "DAILY"
monitor_arn_list = [
aws_ce_anomaly_monitor.linked_account.arn
]
subscriber {
address = aws_sns_topic.cost_alert.arn
type = "SNS"
}
threshold_expression {
dimension {
key = "ANOMALY_TOTAL_IMPACT_PERCENTAGE"
values = ["20"]
match_options = ["GREATER_THAN_OR_EQUAL"]
}
}
}
ANOMALY_TOTAL_IMPACT_PERCENTAGE = 20 は「期待値比 20% 以上のコスト増加」を検知条件とします。本番環境では 10〜20% 程度に設定し、ノイズが多い場合は閾値を引き上げます。
Forecast API は過去 14 日以上のデータが必要です。新規アカウントでは最低 2 週間の実績データが蓄積されるまで Forecast の精度が保証されません。
予算の 80% 到達時に SNS 通知を送り、100% 到達時に EventBridge で自動スケールダウンや非本番リソースの停止を実行するパターンは §4 Budgets 実践で詳述します。
3-5. mermaid01: コスト分析シーケンス
sequenceDiagram
participant Ops as 運用チーム
participant CE as Cost Explorer
participant CUR as CUR (S3 / Parquet)
participant Athena
participant QS as QuickSight
Ops->>CE: 月次コスト確認 (コンソール)
CE-->>Ops: サービス別集計 / 前月比
Ops->>CUR: 詳細データ参照 (Parquet)
CUR->>Athena: Glue Crawler スキャン (毎朝6時)
Athena->>QS: ダッシュボード更新
QS-->>Ops: Tag別 / Account別 詳細分析
Note over Ops,CE: Anomaly Alert は SNS 経由で即時通知
Cost Explorer はリアルタイムに近い集計値を提供しますが、詳細なリソース別 / タグ別分析は CUR + Athena を使います。QuickSight ダッシュボードを構築することで、エンジニア以外のステークホルダーにもコスト状況を共有できます。
Cost Explorer 3鉄則
- 鉄則1 — CUR を設定する前に Cost Allocation Tags を設計せよ: タグ設計なしで CUR を有効化しても Tag 列が空になり、後からプロジェクト別 / チーム別の集計ができない。
CostCenter/Environment/Projectタグを最低限定義してから CUR を有効化する - 鉄則2 — Cross-Account 集約は管理アカウント CUR 一元化で完結させよ: メンバーアカウント個別に CUR を設定すると S3 バケットが乱立し保守コストが増大する。Organizations 管理アカウントの CUR で全アカウントを一元管理する
- 鉄則3 — Forecast API は 14 日以上のデータが存在しないと精度ゼロ: 新規アカウントや新しいサービスを追加した直後は Forecast の信頼区間が非常に広い。最低 2 週間の実績データが蓄積されてから Forecast を活用する
4. Budgets実践 — Budget types / Threshold / SNS通知 / EventBridge自動対応

AWS Budgets は月次コスト・使用量・RI/SP 利用率に対して閾値を設定し、超過時に SNS 通知や Lambda 自動対処を起動するコスト管理サービスだ。§3 の Cost Explorer が「過去を可視化する」のに対して、Budgets は「未来を制御する」役割を担う。Budget types の選定から Terraform 実装、EventBridge 連携による自動対処まで実践的に解説する。
4-1. Budget types 選定ガイド
| Budget type | 監視対象 | 主なユースケース |
|---|---|---|
| Cost Budget | 月次コスト合計 (USD) | 全体コスト上限管理・月次予算超過防止 |
| Usage Budget | 特定サービスの使用量 | EC2 時間・S3 転送量・Lambda 実行回数の上限設定 |
| RI Budget | RI 利用率・カバレッジ | 購入済み RI の消化率監視・未使用 RI の検出 |
| Savings Plans Budget | SP 利用率・カバレッジ | 購入済み Savings Plans の消化率監視 |
目的は何か?
├── コスト総額を管理したい → Cost Budget
├── 特定サービスの使用量を制限したい→ Usage Budget
├── RI を購入済みで消化率が心配 → RI Budget (利用率)
├── RI のカバレッジ (適用率) を上げたい→ RI Budget (カバレッジ)
├── Savings Plans を購入済み → Savings Plans Budget (利用率)
└── SP の適用漏れを防ぎたい → Savings Plans Budget (カバレッジ)
Cost Budget を 1 本だけ設定して満足するのが最も多い失敗パターンだ。RI/SP を購入している環境では、RI Budget と Savings Plans Budget を必ず追加することで、購入コストの無駄を検知できる。
4-2. Threshold + SNS通知 設定 (Terraform)
Budgets の Threshold には ACTUAL (実績) と FORECASTED (予測) の 2 種類がある。ACTUAL のみでは月末に超過確定してから気付くため、FORECASTED を組み合わせて予防的に通知を受け取る設計が実践的だ。
resource "aws_sns_topic" "budget_alert" {
name = "budget-alert-topic"
}
resource "aws_sns_topic_policy" "budget_alert" {
arn = aws_sns_topic.budget_alert.arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "budgets.amazonaws.com" }
Action = "SNS:Publish"
Resource = aws_sns_topic.budget_alert.arn
}]
})
}
resource "aws_budgets_budget" "monthly_cost" {
name= "monthly-cost-budget"
budget_type = "COST"
limit_amount = "1000"
limit_unit= "USD"
time_unit = "MONTHLY"
notification {
comparison_operator = "GREATER_THAN"
threshold = 50
threshold_type= "PERCENTAGE"
notification_type= "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.budget_alert.arn]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type= "PERCENTAGE"
notification_type= "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.budget_alert.arn]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type= "PERCENTAGE"
notification_type= "FORECASTED"
subscriber_sns_topic_arns = [aws_sns_topic.budget_alert.arn]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 120
threshold_type= "PERCENTAGE"
notification_type= "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.budget_alert.arn]
}
}
| 閾値 | 種別 | 対応内容 |
|---|---|---|
| 50% ACTUAL | 情報確認 | 月次コストペースの確認 |
| 80% ACTUAL | 警戒 | コスト増加の要因調査を開始 |
| 100% FORECASTED | 予防的対処 | 月末前に超過確定を防ぐ対策着手 |
| 120% ACTUAL | 緊急対処 | 自動停止ロジックを起動 |
SNS Topic に Budgets からの Publish を許可する aws_sns_topic_policy の設定を忘れるのが典型的な詰まりポイントだ。Principal に budgets.amazonaws.com を指定しないと通知が届かない。
4-3. EventBridge + Lambda 自動対処
resource "aws_cloudwatch_event_rule" "budget_alert" {
name = "budget-cost-overrun-alert"
description = "Route Budget alert to Lambda for auto-response"
event_pattern = jsonencode({
source= ["aws.budgets"]
detail-type = ["Budget Threshold Breached"]
})
}
resource "aws_cloudwatch_event_target" "budget_lambda" {
rule= aws_cloudwatch_event_rule.budget_alert.name
target_id = "BudgetAlertToLambda"
arn = aws_lambda_function.budget_response.arn
}
resource "aws_lambda_permission" "allow_budget_eventbridge" {
statement_id = "AllowExecutionFromEventBridge"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.budget_response.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.budget_alert.arn
}
Lambda 自動対処関数 (Python):
import boto3
import json
ec2 = boto3.client('ec2')
sns = boto3.client('sns')
ALERT_TOPIC = 'arn:aws:sns:ap-northeast-1:123456789012:budget-alert'
def handler(event, context):
message = json.loads(event['Records'][0]['Sns']['Message'])
budget_name = message.get('budgetName', '')
threshold_exceeded = message.get('thresholdExceeded', 0)
# 120% 超過時のみ自動停止 (開発環境の非重要インスタンスのみ対象)
if threshold_exceeded >= 120:
response = ec2.describe_instances(
Filters=[
{'Name': 'tag:Environment', 'Values': ['dev']},
{'Name': 'tag:AutoStop', 'Values': ['true']},
{'Name': 'instance-state-name', 'Values': ['running']}
]
)
instance_ids = [
i['InstanceId']
for r in response['Reservations']
for i in r['Instances']
]
if instance_ids:
ec2.stop_instances(InstanceIds=instance_ids)
sns.publish(
TopicArn=ALERT_TOPIC,
Message=(
f'コスト閾値 120% 超過: 開発環境インスタンスを停止しました\n'
f'停止対象: {instance_ids}\n'
f'Budget: {budget_name}'
),
Subject='Budgets 自動対処 — 開発環境インスタンス停止'
)
return {'statusCode': 200, 'stopped': instance_ids}
return {'statusCode': 200, 'stopped': []}
自動停止の対象は Environment=dev + AutoStop=true タグを持つインスタンスのみに限定する。本番環境インスタンスへの自動停止は重大な影響を及ぼすため、絶対に対象外とする。
| 閾値 | 対処レベル | 実行内容 |
|---|---|---|
| 50% | 通知のみ | 担当者へのメール通知 |
| 80% | 通知のみ | エスカレーション通知 (管理者含む) |
| 100% (FORECASTED) | 軽度制限 | 開発環境の新規インスタンス起動を停止 |
| 120% | 強制停止 | 開発環境の非重要インスタンスを停止 |
4-4. Budgets Actions による IAM/SCP 自動制限
Budgets Actions は Lambda を介さずに直接 IAM Policy の attach/detach・SCP の apply・EC2 インスタンスの停止を自動実行できる機能だ。
resource "aws_budgets_budget_action" "stop_ec2_on_overage" {
budget_name = aws_budgets_budget.monthly_cost.name
action_type = "STOP_EC2_INSTANCES"
approval_model = "AUTOMATIC"
notification_type = "ACTUAL"
action_threshold {
action_threshold_type = "PERCENTAGE"
action_threshold_value = 120
}
definition {
ssm_action_definition {
action_sub_type = "STOP_EC2_INSTANCES"
instance_ids = ["i-dev-instance-01", "i-dev-instance-02"]
region = "ap-northeast-1"
}
}
subscriber {
address = aws_sns_topic.budget_alert.arn
subscription_type = "SNS"
}
}
approval_model に MANUAL を設定すると担当者の承認後に実行され、誤自動対処のリスクを排除できる。本番環境に関わる Actions は必ず MANUAL にすること。
- 鉄則1 — Budget types は用途別に4タイプ使い分けよ: Cost Budget 1本では RI/SP の利用率低下を検知できない。RI/SP を購入している環境では RI Budget と Savings Plans Budget を必ず追加する
- 鉄則2 — ACTUAL と FORECASTED の両方を設定せよ: ACTUAL のみでは月末超過確定後に気付く。FORECASTED を設定することで月末前に予防的な対処ができる
- 鉄則3 — 自動対処は開発環境のみに限定せよ: 本番環境への自動停止は重大な影響リスクがある。本番は通知のみとし、開発環境の AutoStop タグ付きインスタンスのみを自動対処の対象とすること
5. Compute Optimizer実践 — Recommendations / EC2 / EBS / Lambda / Auto Scaling Group

5-1. Compute Optimizer の仕組み
AWS Compute Optimizer は、CloudWatch メトリクスの14日分 (Enhanced Infrastructure Metrics では30日分) を機械学習で分析し、EC2 / EBS / Lambda / ASG / ECS on Fargate のリソースサイジング最適化を推奨するサービスだ。Cost Explorer が「いくら使ったか」を可視化するのに対し、Compute Optimizer は「どう削減できるか」を提示する。
Recommendations の4分類
| Finding | 意味 | 対応方針 |
|---|---|---|
OVER_PROVISIONED | リソースが過剰 (CPU/Memory 低使用率) | Down-size へ変更してコスト削減 |
UNDER_PROVISIONED | リソースが不足 (CPU/Memory 高使用率) | Up-size へ変更してパフォーマンス改善 |
OPTIMIZED | 現状のリソースが最適 | 変更不要 |
NOT_OPTIMIZED | データ不足でまだ分析中 | 14日後に再確認 |
Savings Opportunity
各 Recommendation には savingsOpportunityPercentage (削減可能コスト割合) と estimatedMonthlySavings (月次削減額) が付与される。優先対応順は「削減額の大きいもの」「OVER_PROVISIONED のもの」の順に着手するとコスト削減の費用対効果が高い。
オプトイン設定
Compute Optimizer は有効化しないと動作しない。Organizations 全体で有効化するには管理アカウントの Compute Optimizer → 設定からオプトインする。単一アカウントの場合は各アカウントで個別にオプトインする。
Compute Optimizer 対応リソース一覧
| リソース | Recommendations 内容 | 分析期間 |
|---|---|---|
| EC2 インスタンス | インスタンスタイプ変更 / 右サイジング | 14日 (EIM: 30日) |
| EBS ボリューム | ボリュームタイプ / サイズ最適化 | 14日 |
| Lambda 関数 | メモリサイズ最適化 | 14日 |
| Auto Scaling Group | インスタンスタイプ / Mixed Instance Policy | 14日 |
| ECS on Fargate | CPU / メモリ設定最適化 | 14日 |
| EKS ノード (マネージド) | ノードインスタンスタイプ | 14日 |
いずれのリソースも、データ収集開始から14日経過すると初回の Recommendations が生成される。新規アカウントや新規リソースでは2週間の「ウォームアップ期間」を見込んで計画を立てる。
5-2. EC2 Recommendations
EC2 の右サイジングは Compute Optimizer が最も得意とする領域だ。CPU 使用率・メモリ使用率 (CloudWatch エージェントが必要)・ネットワーク帯域などを複合的に分析し、最適なインスタンスタイプを提案する。
右サイジング基準
- CPU 平均使用率 40% 以下が継続 → Down-size 推奨 (例:
m5.xlarge→m5.large) - Instance family の世代交代:
M5→M6i/T2→T3(同等性能でコスト削減) - Enhanced Infrastructure Metrics (有料) を有効化すると30日分のデータで精度が向上する
boto3 API で Recommendations を一括取得
import boto3
import csv
co = boto3.client('compute-optimizer', region_name='us-east-1')
def get_ec2_recommendations():
paginator = co.get_paginator('get_ec2_instance_recommendations')
recommendations = []
for page in paginator.paginate():
recommendations.extend(page.get('instanceRecommendations', []))
results = []
for rec in recommendations:
opts = rec.get('recommendationOptions', [])
best_opt = opts[0] if opts else {}
savings = rec.get('savingsOpportunity', {})
results.append({
'instanceArn':rec['instanceArn'],
'finding': rec['finding'],
'currentInstanceType': rec.get('currentInstanceType', ''),
'recommendedInstanceType': best_opt.get('instanceType', 'N/A'),
'savingsOpportunityPct': savings.get('savingsOpportunityPercentage', 0),
'estimatedMonthlySavings': savings.get('estimatedMonthlySavings', {}).get('value', 0),
})
return results
recs = get_ec2_recommendations()
with open('ec2_recommendations.csv', 'w', newline='', encoding='utf-8') as f:
fieldnames = ['instanceArn', 'finding', 'currentInstanceType',
'recommendedInstanceType', 'savingsOpportunityPct', 'estimatedMonthlySavings']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(recs)
print(f"Total recommendations: {len(recs)}")
over_provisioned = [r for r in recs if r['finding'] == 'OVER_PROVISIONED']
total_savings = sum(r['estimatedMonthlySavings'] for r in over_provisioned)
print(f"OVER_PROVISIONED: {len(over_provisioned)} instances, estimated savings: ${total_savings:.2f}/month")
ページネーション対応で大規模アカウントでも全 Recommendations を取得できる。CSV 出力後は Excel / Google Sheets でフィルタリングし、削減額上位から優先的に変更作業を進める。
EC2 インスタンスファミリー移行パス早見表
| 現世代 | 推奨移行先 | コスト削減率 | 備考 |
|---|---|---|---|
m5.xlarge | m6i.xlarge | 〜5% | 同ファミリー最新世代・互換性高 |
m5.xlarge | m6g.xlarge (Graviton3) | 〜20% | arm64 対応アプリで最大効果 |
t2.medium | t3.medium | 〜10% | CPU クレジット機構が改善 |
c5.2xlarge | c6i.2xlarge | 〜5% | コンピュート最適化ファミリー |
r5.4xlarge | r6i.4xlarge | 〜5% | メモリ最適化ファミリー |
Graviton (ARM64) 移行は最大 20% のコスト削減が期待できるが、アプリケーションの arm64 対応を CI/CD パイプラインでクロスコンパイルテストしてから適用する。Compute Optimizer は arm64 互換性の情報を提供しないため、互換性確認は運用チームの責任で行う。
5-3. EBS + Lambda + ASG Recommendations
EBS — gp2 → gp3 移行
Compute Optimizer は EBS ボリュームの使用パターンを分析し、gp2 から gp3 への移行を推奨することがある。gp3 は gp2 と同等性能でコストが約 20% 削減でき、IOPS とスループットを独立して設定できる。
# gp2 → gp3 変更 (AWS CLI)
aws ec2 modify-volume--volume-id vol-0a1b2c3d4e5f67890--volume-type gp3--iops 3000--throughput 125
変更はオンラインで実行でき、EC2 インスタンスを停止する必要はない。Compute Optimizer が推奨する IOPS / Throughput 値をそのまま使うか、使用パターンに応じて調整する。
Lambda — メモリ最適化
Lambda の Recommendations ではメモリサイズの過剰割り当てを検出する。メモリが多すぎると実行コストが増大するが、少なすぎると実行時間が伸びてかえって高コストになる。Compute Optimizer が提案する最適メモリ値に変更することで、コストと実行時間の両方を改善できる。
Lambda の課金は 実行時間 (ms) × メモリサイズ (GB) に比例する。メモリを増やすことで実行時間が短縮される場合、総コストが変わらない「等コストポイント」が存在する:
| メモリ設定 | 仮想実行時間 | コスト単位 (GB-ms) | 月次コスト傾向 |
|---|---|---|---|
| 128 MB | 3,200 ms | 409.6 GB-ms | 低コスト・高レイテンシ |
| 512 MB | 800 ms | 409.6 GB-ms | 等コスト・低レイテンシ |
| 1,024 MB | 500 ms | 512.0 GB-ms | コスト増・最低レイテンシ |
| 2,048 MB | 500 ms | 1,024.0 GB-ms | 過剰メモリ・コスト2倍 |
Compute Optimizer は実測データからこの変曲点を特定し、コストと実行速度のバランスが最良なメモリ設定を提示する。
ASG — Mixed Instance Policy
ASG の Recommendations では、単一インスタンスタイプから Mixed Instance Policy への移行を提案する。Spot Instance を組み合わせることで EC2 コストを大幅に削減できる。ただし Spot は中断リスクがあるため、中断許容バッチワークロードへの適用を優先する。
Mixed Instance Policy では複数のインスタンスタイプとキャパシティ比率を指定し、Spot 調達失敗時にも On-Demand で補完する構成を組める:
| 構成例 | Spot 割合 | On-Demand 割合 | コスト削減目安 |
|---|---|---|---|
| 本番 Web 層 | 0% | 100% | なし (安定性優先) |
| ステージング | 70% | 30% | 約 40% |
| バッチ / ML 学習 | 100% | 0% | 最大 90% |
| EKS ノード (非クリティカル) | 80% | 20% | 約 60% |
Compute Optimizer が ASG に Mixed Instance Policy を推奨した場合、CloudFormation / Terraform で MixedInstancesPolicy ブロックを追加し、複数インスタンスタイプ (m5.large, m6i.large, m5a.large など) を候補に設定すると Spot 調達率が向上する。
5-4. EKS ノード最適化 + Recommendations 適用フロー
EKS Vol1 との架橋
EKS 本番運用 Vol1: Cluster 設計 / IRSA / ALB で設計した EKS マネージドノードグループも Compute Optimizer の分析対象だ。Worker ノードの EC2 インスタンスタイプが過剰な場合、Recommendations が提示される。Karpenter と組み合わせると、Recommendations の最適インスタンスタイプを NodePool に設定して自動的に最適化を継続できる。
Karpenter NodePool への Recommendations 反映
Compute Optimizer が m5.xlarge → m6i.large への Down-size を推奨した場合、Karpenter NodePool の instanceGeneration 条件を更新することで最適世代のインスタンスを自動選択できる:
# karpenter-nodepool-optimized.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: general-optimized
spec:
template:
spec:
requirements:
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["m", "c"] # Compute Optimizer 推奨ファミリー
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["5"]# M5以上 → M6i / M7i が選択される
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"] # Spot 優先でコスト最適化
limits:
cpu: "500"
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 30s# 未使用ノードは30秒後に自動回収
consolidateAfter: 30s により Karpenter が定期的にノードをコンソリデーションし、Compute Optimizer の Recommendations と連動した継続的な右サイジングを実現する。
Recommendations 適用フロー (Mermaid02)
flowchart TD
A[CloudWatch Metrics<br/>14日分収集] --> B[Compute Optimizer<br/>ML分析エンジン]
B --> C{Finding}
C -->|OVER_PROVISIONED| D[Down-size<br/>推奨]
C -->|UNDER_PROVISIONED| E[Up-size<br/>推奨]
C -->|OPTIMIZED| F[現状維持<br/>確認]
D --> G[Recommendations<br/>API / Console 確認]
E --> G
G --> H{承認}
H -->|自動適用| I[Lambda<br/>自動変更]
H -->|手動適用| J[運用チーム<br/>変更作業]
I --> K[CloudWatch<br/>効果測定]
J --> K
| 選定基準 | Reserved Instance | Savings Plans | Spot Instance |
|---|---|---|---|
| ワークロード種別 | 特定サービス固定 | 柔軟なコンピュート | 中断許容バッチ |
| 割引率 | 最大 72% | 最大 66% | 最大 90% |
| コミット期間 | 1年 / 3年 | 1年 / 3年 | なし |
| 向き不向き | RDS / ElastiCache / Redshift | EC2 / Fargate / Lambda | ML 学習 / 大規模バッチ |
AWS Compute Optimizer 公式ドキュメント
6. 詰まりポイント7選 図解
6-1. Cost Allocation Tags 設計ミス(大文字/小文字不統一 / Key設計不足)
Cost Allocation Tags はコスト配分の要だが、タグキーの大文字/小文字の揺れや命名規約の欠如が後から深刻な集計漏れを引き起こす。AWS タグは大文字小文字を区別するため、Environment と environment は別タグとして扱われ、Cost Explorer のフィルタが分断される。
根本原因: タグ設計をチーム横断で標準化していない。Terraform module ごとにタグを手書きし、レビュー漏れで揺れが発生する。
正しい設計例:
# variables.tf — 全モジュール共通タグを locals で一元管理
locals {
common_tags = {
Environment = var.environment# 大文字始まり固定
Project = var.project_name
CostCenter = var.cost_center
Team = var.team_name
ManagedBy= "terraform"
}
}
resource "aws_instance" "app" {
ami = var.ami_id
instance_type = var.instance_type
tags = merge(local.common_tags, {
Name = "${var.project_name}-app-${var.environment}"
})
}
- Terraform の
locals.common_tagsで全タグを一元管理し、全リソースにmerge()で適用する - AWS Organizations の Tag Policy でキー名・値パターンを強制し、違反リソースを AWS Config で検出する
- Cost Allocation Tags は AWS Billing Console で明示的に「有効化」しないと Cost Explorer に現れない点に注意
6-2. Cross-Account 集約で管理アカウントのコストが不明(CUR 設定漏れ)
AWS Organizations で複数アカウントを管理している場合、CUR(Cost and Usage Report)を管理アカウント側でしか有効化しておらず、各メンバーアカウントのコストが集約されないケースが多い。
根本原因: CUR を設定した管理アカウントの Linked Accounts データは自動的に集約されるが、linked_account_ids フィルタや Athena パーティション設定を誤ると特定アカウントが集計から漏れる。
正しい設定例:
resource "aws_cur_report_definition" "main" {
report_name = "organization-cur"
time_unit= "HOURLY"
format= "Parquet"
compression = "Parquet"
additional_schema_elements = ["RESOURCES"]
s3_bucket= aws_s3_bucket.cur.bucket
s3_region= "us-east-1"# CUR は us-east-1 のみ
s3_prefix= "cur"
report_versioning = "OVERWRITE_REPORT"
refresh_closed_reports = true
# Organizations 全アカウントを含める
additional_artifacts = ["ATHENA"]
}
- CUR は必ず管理アカウント(Payer Account)で有効化し、
additional_artifacts = ["ATHENA"]を指定して Athena クローラを自動生成する s3_region = "us-east-1"は固定(CUR S3 バケットは us-east-1 のみ対応)- Athena のパーティション射影を設定し、月次スキャンコストを最小化する
6-3. Reserved Instance 購入タイミング失敗(Expiry 前のリニューアル漏れ)
RI(Reserved Instance)は 1 年または 3 年の固定契約で、有効期限が切れると即座にオンデマンド料金に戻る。有効期限管理を自動化せず、気づいたら数日オンデマンドで動いていたというケースが頻発する。
根本原因: RI 有効期限の通知設定をしていない。購入時は覚えているが、12〜36 か月後には担当者が変わっていることも多い。
自動監視 Lambda(Python):
import boto3
from datetime import datetime, timezone, timedelta
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name='us-east-1')
sns = boto3.client('sns')
response = ec2.describe_reserved_instances(
Filters=[{'Name': 'state', 'Values': ['active']}]
)
expiring_soon = []
threshold = datetime.now(timezone.utc) + timedelta(days=30)
for ri in response['ReservedInstances']:
end_time = ri['End']
if end_time < threshold:
expiring_soon.append({
'id': ri['ReservedInstancesId'],
'instance_type': ri['InstanceType'],
'end': end_time.isoformat(),
'count': ri['InstanceCount']
})
if expiring_soon:
message = "RI 有効期限 30日以内:\n" + "\n".join(
f"- {r['id']}: {r['instance_type']} x{r['count']} (期限: {r['end']})"
for r in expiring_soon
)
sns.publish(TopicArn=event['sns_topic_arn'], Message=message,
Subject="【警告】RI 有効期限切れ間近")
return {'expiring_count': len(expiring_soon)}
- EventBridge ScheduledRule(毎日 09:00 JST)で Lambda を起動し、30 日以内に期限切れの RI を SNS に通知する
- AWS Budgets の RI Utilization / Coverage アラートも併用し、使用率 80% 未満を検知する
- RI 更新は購入済み RI の期限直前にコンソールから Renew を選択するか、新規 RI を購入して切り替える
6-4. Savings Plans 選定ミス(Compute SP vs EC2 Instance SP)
Savings Plans には Compute SP と EC2 Instance SP の 2 種類があり、誤った方を選ぶとコスト削減効果が激減する。EC2 Instance SP はインスタンスファミリー・リージョン固定で最大 72% 削減だが、Compute SP は EC2・Fargate・Lambda に横断適用できる代わりに割引率が最大 66% と若干低い。
根本原因: 「柔軟性が高い Compute SP を選べばよい」と考えてしまい、実際にはほぼ EC2 の同一インスタンスファミリーしか使わないケースで損をする。
判断フローチャート(テキスト):
ワークロードの柔軟性は?
├─ EC2 のみ・インスタンスファミリー固定 → EC2 Instance SP (最大 72% 割引)
├─ EC2 のみ・将来ファミリー変更予定あり → Compute SP (最大 66% 割引)
├─ Fargate / Lambda も含む → Compute SP 一択
└─ 不明・混在 → まず Compute Optimizer の推奨を確認してから判断
コミットメント量の計算:
# Cost Explorer API でオンデマンド支出を取得してコミット量を推定
import boto3
ce = boto3.client('ce', region_name='us-east-1')
response = ce.get_savings_plans_purchase_recommendation(
SavingsPlansType='COMPUTE_SP',
TermInYears='ONE_YEAR',
PaymentOption='NO_UPFRONT',
LookbackPeriodInDays='THIRTY_DAYS'
)
rec = response['SavingsPlansRecommendation']
print(f"推奨コミット量: ${rec['SavingsPlansPurchaseRecommendationSummary']['HourlyCommitmentToPurchase']}/hour")
print(f"推定節約額: ${rec['SavingsPlansPurchaseRecommendationSummary']['EstimatedSavingsAmount']}/month")
- Cost Explorer の「Savings Plans 購入推奨」で推奨コミット量・節約額・カバレッジを確認してから購入する
- EC2 Instance SP と Compute SP の割引率差(最大 6%)とワークロード柔軟性を天秤にかける
- コミット量は過去 30 日のオンデマンド支出の 70〜80% から始めて段階的に引き上げる
6-5. Spot Instance 中断への備えなし(Termination Notice 未対応)
Spot Instance は最大 90% 削減できるが、AWS が容量を必要とする際に 2 分前通知で中断される。この通知を処理せずに突然インスタンスが消えると、処理中のジョブデータが失われる。
根本原因: Spot Instance Termination Notice(EC2 インスタンスメタデータ spot/termination-time)をポーリングするコードを書いていない。
Termination Notice 対応コード(Python):
import requests
import signal
import sys
import boto3
import time
METADATA_URL = "http://169.254.169.254/latest/meta-data/spot/termination-time"
def check_termination():
try:
resp = requests.get(METADATA_URL, timeout=1)
return resp.status_code == 200
except requests.exceptions.RequestException:
return False
def save_checkpoint(s3_client, bucket, key, state):
s3_client.put_object(
Bucket=bucket,
Key=key,
Body=str(state).encode('utf-8')
)
def main():
s3 = boto3.client('s3')
checkpoint_bucket = "my-checkpoint-bucket"
checkpoint_key = f"checkpoints/{get_instance_id()}.json"
job_state = {"processed_items": 0}
while True:
if check_termination():
# 中断通知を検知 → チェックポイント保存
save_checkpoint(s3, checkpoint_bucket, checkpoint_key, job_state)
sys.exit(0) # graceful shutdown
# 通常処理
process_batch(job_state)
time.sleep(5) # 5 秒ごとにポーリング
def get_instance_id():
resp = requests.get(
"http://169.254.169.254/latest/meta-data/instance-id", timeout=1
)
return resp.text
- 5 秒ごとに EC2 メタデータエンドポイントをポーリングし、HTTP 200 が返ったら 2 分以内に処理を終わらせる
- 進捗を S3 にチェックポイント保存し、再起動後に続きから再開できる設計にする
- Auto Scaling Group の Spot + On-Demand 混在構成(baseCapacity=1)で中断時の影響を最小化する
6-6. Data Transfer 隠れコスト(NAT Gateway / ALB / Cross-AZ)
EC2 や RDS の料金だけを見ていると、月次請求書で NAT Gateway のデータ転送料金が予想外に高いことに驚く。NAT Gateway は $0.045/GB、Cross-AZ 転送は $0.01/GB、S3 インターネット転送は $0.09/GB(最初の 10 TB)が発生する。
根本原因: アーキテクチャ設計時にデータ転送パスを可視化せず、「とりあえず NAT Gateway 経由」で設計してしまう。
VPC エンドポイントによる NAT Gateway コスト削減(Terraform):
# S3 Gateway エンドポイント(無料)— NAT Gateway 経由を回避
resource "aws_vpc_endpoint" "s3" {
vpc_id= aws_vpc.main.id
service_name= "com.amazonaws.${var.aws_region}.s3"
vpc_endpoint_type = "Gateway"
route_table_ids= aws_route_table.private[*].id
}
# DynamoDB Gateway エンドポイント(無料)
resource "aws_vpc_endpoint" "dynamodb" {
vpc_id= aws_vpc.main.id
service_name= "com.amazonaws.${var.aws_region}.dynamodb"
vpc_endpoint_type = "Gateway"
route_table_ids= aws_route_table.private[*].id
}
# ECR Interface エンドポイント($0.01/h だが大量イメージ pull で NAT より安い)
resource "aws_vpc_endpoint" "ecr_dkr" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.ecr.dkr"
vpc_endpoint_type= "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpc_endpoint.id]
private_dns_enabled = true
}
復旧・運用編 Vol4: Multi-Region A/A 構成では cross-region Data Transfer cost が課題になりやすく、リージョン間の冗長化コストを Cost Explorer で事前試算することが必須です。
AI シリーズ Vol1: Bedrock Agents での model invocation cost は Bedrock pricing page で確認してください。入力トークン・出力トークン・Knowledge Base ベクトルクエリのそれぞれに課金が発生します。
セキュリティ本格運用 Vol1 の Security Hub Aggregator を有効化すると、1 アカウントあたり月 $10〜30 の追加コストが発生するため、Cost Budgets で監視することを推奨します。
- S3・DynamoDB は Gateway エンドポイント(無料)で NAT Gateway を完全にバイパスする
- ECR・Secrets Manager などは Interface エンドポイントを検討(大量トラフィック時に NAT より安い)
- Cross-AZ 転送は ALB ターゲットグループの AZ ローカル優先設定(
load_balancing.cross_zone.enabled = false)で削減可能 - Cost Explorer の「サービス別コスト」で EC2-Other(NAT Gateway 転送料金)を定期確認する
6-7. Tag-based Cost Report の集計漏れ(Untagged リソース問題)
タグベースのコストレポートで「Untagged」カテゴリが全体の 20〜40% を占めることがある。タグを付けていないリソース(スナップショット、古い EBS ボリューム、自動生成されたセキュリティグループ等)がコスト配分から漏れる。
根本原因: リソース作成時にタグを付けても、後から作成されるスナップショットや派生リソースにはタグが引き継がれない場合がある。また、Terraform 管理外のリソースや手動作成リソースにタグが付いていない。
Untagged リソース検出スクリプト(Python):
import boto3
def find_untagged_resources(required_tags):
"""必須タグのないリソースを検出する"""
tagging = boto3.client('resourcegroupstaggingapi', region_name='us-east-1')
untagged = []
paginator = tagging.get_paginator('get_resources')
for page in paginator.paginate(
TagFilters=[], # 全リソースを取得
ResourceTypeFilters=['ec2:instance', 'ec2:volume', 'rds:db', 's3']
):
for resource in page['ResourceTagMappingList']:
existing_keys = {t['Key'] for t in resource.get('Tags', [])}
missing = set(required_tags) - existing_keys
if missing:
untagged.append({
'arn': resource['ResourceARN'],
'missing_tags': list(missing)
})
return untagged
if __name__ == '__main__':
required = ['Environment', 'Project', 'CostCenter', 'Team']
results = find_untagged_resources(required)
print(f"Untagged リソース: {len(results)} 件")
for r in results[:10]: # 先頭 10 件表示
print(f" {r['arn']}: 欠落タグ={r['missing_tags']}")
- AWS Config の
required-tagsマネージドルールで、必須タグのないリソースを自動検出・通知する - EC2 の「インスタンス起動時のタグコピー」設定を有効化し、スナップショット・AMI にタグを自動引き継ぎする
- 週次で Resource Tagging API を Lambda から呼び出し、Untagged リソースリストを S3 に出力して Cost Center オーナーに通知する
7. アンチパターン→正解パターン変換演習 (Terraform + CUR yaml + Lambda 3形式)
本セクションでは「壊れたコードを直せ」方式で、実際の現場でよく見かけるミス設定を修正する演習を 5 問用意しました。各演習は ❌ 問題コード → ✅ 正解コード → ポイント解説の構成です。
演習 1: Cost Allocation Tags の大文字/小文字不統一を修正(Terraform)
❌ 問題のコード(どこが問題か?)
# 問題: チームごとにタグキーの大文字小文字が揺れている
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.medium"
tags = {
environment = "production"# 問題: 小文字
Project = "myapp"
cost_center = "engineering" # 問題: snake_case
team = "backend"# 問題: 小文字
}
}
resource "aws_instance" "db" {
ami = "ami-0abcdef1234567890"
instance_type = "r5.large"
tags = {
Environment = "production"# web と不統一
project = "myapp" # 問題: 小文字
CostCenter = "engineering" # 問題: cost_center と不統一
Team = "backend"
}
}
✅ 正解コード(解説付き)
# 解決: locals で共通タグを一元管理し、全リソースに merge で適用
locals {
# 命名規約: PascalCase 固定、全タグをここで定義
common_tags = {
Environment = var.environment# Production / Staging / Development
Project = var.project_name
CostCenter = var.cost_center
Team = var.team_name
ManagedBy= "terraform"
}
}
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = "t3.medium"
tags = merge(local.common_tags, {
Name = "${var.project_name}-web-${var.environment}"
Role = "web"
})
}
resource "aws_instance" "db" {
ami = var.ami_id
instance_type = "r5.large"
tags = merge(local.common_tags, {
Name = "${var.project_name}-db-${var.environment}"
Role = "database"
})
}
ポイント解説: locals.common_tags を単一ファイル(locals.tf)で管理し、全リソースで merge() を使う。AWS Organizations の Tag Policy でキー名・値パターンを強制し、違反を AWS Config で検出する仕組みと組み合わせると効果的です。
演習 2: CUR S3 設定の region 誤り + Athena 連携漏れを修正(Terraform)
❌ 問題のコード
resource "aws_cur_report_definition" "bad" {
report_name = "my-cur"
time_unit= "DAILY"
format= "textORcsv"# 問題: Athena非対応形式
compression = "GZIP"
additional_schema_elements = ["RESOURCES"]
s3_bucket= "my-cur-bucket"
s3_region= "ap-northeast-1" # 問題: CURはus-east-1のみ
s3_prefix= "cur"
report_versioning = "CREATE_NEW_REPORT"
# 問題: additional_artifacts が未設定 → Athena クローラ未生成
}
✅ 正解コード
resource "aws_cur_report_definition" "main" {
report_name = "organization-cur"
time_unit= "HOURLY" # 修正: コスト詳細分析にはHOURLY推奨
format= "Parquet" # 修正: Athena対応形式
compression = "Parquet" # 修正: Parquetと一致
additional_schema_elements = ["RESOURCES"]
s3_bucket= aws_s3_bucket.cur.bucket
s3_region= "us-east-1" # 修正: CURはus-east-1固定
s3_prefix= "cur"
report_versioning = "OVERWRITE_REPORT" # 修正: 上書きで差分管理
refresh_closed_reports = true
additional_artifacts = ["ATHENA"] # 修正: Athenaクローラ自動生成
}
# CURバケットはus-east-1に作成すること
resource "aws_s3_bucket" "cur" {
provider = aws.us_east_1# us-east-1 プロバイダを使用
bucket= "my-org-cur-${data.aws_caller_identity.current.account_id}"
}
ポイント解説: CUR は AWS 側の制約で S3 バケットが us-east-1 でなければ作成できません。また format = "Parquet" + additional_artifacts = ["ATHENA"] の組み合わせで Glue クローラが自動生成され、Athena からすぐにクエリできます。
演習 3: Budgets の FORECASTED 通知設定漏れを修正(Terraform)
❌ 問題のコード
resource "aws_budgets_budget" "monthly" {
name= "monthly-cost-budget"
budget_type = "COST"
limit_amount = "1000"
limit_unit= "USD"
time_unit = "MONTHLY"
# 問題: ACTUAL のみで FORECASTED 通知がない
# → 月末に予算超過を知っても手遅れ
notification {
comparison_operator = "GREATER_THAN"
threshold= 100
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["team@example.com"]
}
}
✅ 正解コード
resource "aws_budgets_budget" "monthly" {
name= "monthly-cost-budget"
budget_type = "COST"
limit_amount = "1000"
limit_unit= "USD"
time_unit = "MONTHLY"
# 80% ACTUAL: 早期警告
notification {
comparison_operator = "GREATER_THAN"
threshold= 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["team@example.com"]
subscriber_sns_topic_arns = [aws_sns_topic.budget_alert.arn]
}
# 100% FORECASTED: 予測超過を事前に検知
notification {
comparison_operator = "GREATER_THAN"
threshold= 100
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED" # 修正: 予測通知を追加
subscriber_email_addresses = ["team@example.com"]
subscriber_sns_topic_arns = [aws_sns_topic.budget_alert.arn]
}
# 120% ACTUAL: 緊急アラート
notification {
comparison_operator = "GREATER_THAN"
threshold= 120
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_email_addresses = ["oncall@example.com"]
subscriber_sns_topic_arns = [aws_sns_topic.budget_alert.arn]
}
}
ポイント解説: FORECASTED 通知を追加することで、月途中で「このままでは予算超過する」と予測された時点でアラートを受け取れます。80% ACTUAL → 100% FORECASTED → 120% ACTUAL の 3 段階通知が実践的な設定です。
演習 4: Compute Optimizer API でページネーションを正しく実装(Python)
❌ 問題のコード
import boto3
def get_recommendations():
co = boto3.client('compute-optimizer', region_name='us-east-1')
# 問題: ページネーションなし → 100件しか取得できない
response = co.get_ec2_instance_recommendations()
for rec in response['instanceRecommendations']:
print(f"{rec['instanceArn']}: {rec['finding']}")
✅ 正解コード
import boto3
def get_all_recommendations():
co = boto3.client('compute-optimizer', region_name='us-east-1')
recommendations = []
# 修正: paginator を使ってすべてのページを取得
paginator = co.get_paginator('get_ec2_instance_recommendations')
for page in paginator.paginate(
filters=[
{
'name': 'Finding',
'values': ['OVER_PROVISIONED', 'UNDER_PROVISIONED']
}
]
):
for rec in page['instanceRecommendations']:
if rec['recommendationOptions']:
best_option = rec['recommendationOptions'][0]
recommendations.append({
'arn': rec['instanceArn'],
'current': rec['currentInstanceType'],
'recommended': best_option['instanceType'],
'saving': best_option.get('estimatedMonthlySavings', {}).get('value', 0),
'finding': rec['finding']
})
# 節約額の大きい順にソート
recommendations.sort(key=lambda x: x['saving'], reverse=True)
total_saving = sum(r['saving'] for r in recommendations)
print(f"最適化対象: {len(recommendations)} インスタンス")
print(f"推定月次節約額合計: ${total_saving:.2f}")
return recommendations
if __name__ == '__main__':
recs = get_all_recommendations()
for r in recs[:5]:
print(f" {r['arn'].split('/')[-1]}: {r['current']} → {r['recommended']} (${r['saving']:.2f}/月)")
ポイント解説: Compute Optimizer API はデフォルト 100 件制限があります。get_paginator() を使わないと全件取得できず、大規模環境では最適化機会を見逃します。OVER_PROVISIONED と UNDER_PROVISIONED の両方をフィルタに含め、節約額の大きい順に優先対応します。
演習 5: Savings Plans Purchase Order のコミット量設定ミスを修正(Terraform)
❌ 問題のコード
# 問題: コミット量が月額ではなく時間額で計算すべきなのに、月額をそのまま入力している
# → 実際の30倍のコミットになる可能性
resource "aws_savingsplans_savings_plan" "bad" {
savings_plan_type = "COMPUTE"
commitment = "500" # 問題: 500 USD/hour は月 360,000 USD
term_duration = "31536000" # 1年 (秒)
payment_option = "NO_UPFRONT"
}
✅ 正解コード
# 修正: commitment は USD/hour で設定
# 月 $3,000 の支出を SP でカバーしたい場合:
# 3,000 USD/month ÷ 730 hours/month ≈ 4.11 USD/hour
locals {
# 月次コスト目標から時間コミット量を計算
monthly_target_usd = 3000
hours_per_month = 730
# 過去30日のオンデマンド支出の70-80%からスタート推奨
commitment_ratio= 0.75
hourly_commitment = (local.monthly_target_usd * local.commitment_ratio) / local.hours_per_month
}
resource "aws_savingsplans_savings_plan" "main" {
savings_plan_type = "COMPUTE"
commitment = format("%.2f", local.hourly_commitment) # 例: "3.08"
term_duration = "31536000"# 1年 (秒) = 365 × 24 × 3600
payment_option = "NO_UPFRONT"
tags = {
Name = "compute-savings-plan-1y"
Environment = "production"
ManagedBy= "terraform"
}
}
output "hourly_commitment" {
value = format("$%.2f/hour", local.hourly_commitment)
description = "Savings Plans 時間コミット量"
}
ポイント解説: commitment フィールドは USD/hour で指定します。月次コスト目標を 730(月の平均時間数)で割ることで正しい値が得られます。過去 30 日のオンデマンド支出の 70〜80% から開始し、Coverage が 80% を超えたら段階的に引き上げるアプローチが安全です。Cost Explorer の購入推奨(get_savings_plans_purchase_recommendation API)の値を参考にするのが最も確実です。
8. まとめ + Vol2予告 + 落とし穴10選 + 全シリーズクロスリンク + AWS本番運用6軸完結宣言
8-1. 本記事で学んだこと
本記事では、AWS コスト最適化の基礎として Cost Explorer・AWS Budgets・Compute Optimizer の 3 つのコアサービスを実践的に解説しました。
- Cost Explorer: アカウント・サービス・タグ別のコスト分析、RI/Savings Plans 推奨、月次トレンド把握
- AWS Budgets: 予算アラート(ACTUAL + FORECASTED の 2 段階)、RI/SP カバレッジ・使用率監視
- Compute Optimizer: EC2・RDS・Lambda・ECS の最適インスタンスタイプ推奨、最大 25% コスト削減
- Cost Allocation Tags: チーム・プロジェクト・コストセンター別の配分可視化
- CUR + Athena: 詳細データを S3 に蓄積し、SQL で任意の分析が可能
- EventBridge 自動化: Savings Plans 使用率・RI 有効期限を Lambda で定期チェック
8-2. 落とし穴 10 選
| # | 落とし穴 | 影響 | 対策の要点 |
|---|---|---|---|
| 1 | Cost Allocation Tags の大文字小文字不統一 | 集計分断・コスト配分不能 | locals.common_tags で一元管理 |
| 2 | CUR S3 バケットを ap-northeast-1 に作成 | CUR 作成エラー | s3_region = "us-east-1" 固定 |
| 3 | CUR に additional_artifacts = ["ATHENA"] 未設定 | Athena 連携不可 | Parquet 形式 + ATHENA artifact |
| 4 | Budgets 通知が ACTUAL のみ | 月末に気づいて手遅れ | FORECASTED 通知を必ず追加 |
| 5 | RI 有効期限管理を手動で実施 | Expiry 後オンデマンド料金に戻る | EventBridge + Lambda で 30 日前通知 |
| 6 | Savings Plans のコミット量を月額で入力 | 30 倍超のコミットになる事故 | 必ず USD/hour で計算して入力 |
| 7 | Spot Instance の Termination Notice 未対応 | 処理中データが消える | 5 秒ポーリング + S3 チェックポイント |
| 8 | NAT Gateway 経由で S3 に大量転送 | データ転送費が EC2 費を上回る | S3 Gateway エンドポイント(無料)を使う |
| 9 | Compute Optimizer API でページネーションなし | 100 件超の推奨を見逃す | get_paginator() で全件取得 |
| 10 | Untagged リソースが 20〜40% を占める | コスト配分が不正確 | AWS Config required-tags ルールで継続検出 |
8-3. Vol2 予告: Reserved Instance × Savings Plans 完全ガイド
本記事(Vol1)では Cost Explorer・Budgets・Compute Optimizer の基礎を学びました。次の Vol2 では RI と Savings Plans の購入戦略を深堀りします。
- RI 種別完全比較: Standard RI vs Convertible RI vs Scheduled RI — 用途別最適解
- SP 購入戦略: 段階的コミット量引き上げ、Portfolio 管理、Multi-Account 適用
- RI Marketplace: 不要な RI を売却してキャッシュフローを最適化
- SP + RI 組み合わせ: ベースロードを RI でカバーし、変動分を SP で吸収するハイブリッド戦略
8-4. コスト最適化成熟度ロードマップ
コスト最適化は一度設定して終わりではなく、段階的に成熟させる継続的なプロセスです。以下のロードマップを参考に、現在の成熟度を確認してください。
フェーズ 1: 可視化(導入初期)
– Cost Explorer でサービス別・アカウント別コストを把握
– AWS Budgets で月次予算アラートを設定(最低 3 通知)
– Cost Allocation Tags を有効化し、プロジェクト別コストを追跡開始
– CUR を S3 に出力し、Athena でアドホッククエリを可能にする
フェーズ 2: 最適化(3 か月後)
– Compute Optimizer の推奨を全リソースに適用(過剰プロビジョニング解消)
– RI または Savings Plans でベースロードをカバー(最初は 60〜70% コミット)
– VPC Gateway エンドポイントで NAT Gateway コストを削減
– Spot Instance + Auto Scaling でバッチ処理コストを最大 90% 削減
フェーズ 3: 自動化(6 か月後)
– EventBridge + Lambda で RI 有効期限・SP 使用率を自動監視
– AWS Config required-tags ルールで Untagged リソースを継続検出
– Cost Explorer API で月次コストレポートを自動生成・Slack 通知
– Compute Optimizer API で週次推奨サマリを自動レポート化
フェーズ 4: FinOps 文化醸成(1 年後)
– チーム別コストダッシュボードを Grafana/QuickSight で構築
– 月次 FinOps レビュー会議でコスト KPI を経営指標に組み込む
– RI/SP カバレッジ目標 80% 以上を SRE の運用目標に設定
– 新規アーキテクチャのコスト試算を設計レビューの必須チェック項目に
8-5. 本番リリース前コスト最適化チェックリスト
本番リリース前に以下を確認し、コスト爆発を事前に防いでください。
- [ ] Cost Allocation Tags が全リソースに付与されている(AWS Config
required-tagsルール緑) - [ ] AWS Budgets が設定済み(ACTUAL 80% + FORECASTED 100% + ACTUAL 120% の 3 通知)
- [ ] CUR が有効化され、Athena でクエリできる状態
- [ ] S3・DynamoDB への通信に VPC Gateway エンドポイントを使用
- [ ] Compute Optimizer の推奨を確認し、過剰プロビジョニングリソースを最適化
- [ ] RI または Savings Plans でベースロードをカバー
- [ ] Spot Instance を使う場合、Termination Notice 処理を実装済み
8-5. AWS 本番運用 6 軸 完結宣言 + 全シリーズクロスリンク
本記事でAWS本番運用の6軸 (IAM / EKS / 復旧・運用 / AI / セキュリティ / コスト最適化) が揃いました。
コスト最適化シリーズ: Vol1 (本記事): Cost Explorer × Budgets × Compute Optimizer / Vol2 (近日公開): Reserved Instance × Savings Plans
IAM入門4巻: Vol1 / Vol2 / Vol3 / Vol4
復旧・運用編4巻: Vol1 / Vol2 / Vol3 / Vol4
AIシリーズ Vol1: Bedrock Agents 本番運用
セキュリティ本格運用 Vol1: Security Hub × GuardDuty × Audit Manager
セキュリティ本格運用 Vol2: GuardDuty × Security Hub × Detective 統合運用 (SOC実践)
DevOps/CI/CD実践入門 Vol1: CodePipeline × CodeBuild × CodeDeploy × GitHub Actions
DevOps/CI/CD実践 Vol2: Container CD × CodeArtifact × SAM Pipeline × Amplify Hosting
Database本番運用 Vol1: Database本番運用入門 Vol1 — RDS × Aurora × DynamoDB
Database本番運用 Vol2: Database本番運用 Vol2 — DMS × Aurora Global Database × DynamoDB Streams × Backup戦略
Serverless本番運用 Vol1: Serverless本番運用入門 Vol1 — Lambda × API Gateway × Step Functions
Serverless本番運用 Vol2: Serverless本番運用 Vol2 — EventBridge × SQS × SNS × Kinesis
ECSデプロイ自動化: ecspresso v2×Terraform 1.x×AWS Provider 6.x ECS本番運用デプロイ完全ガイド — ecspressoでECSサービスデプロイを自動化しTerraformと責任境界を明確化する実践統合ガイド。
WAF WebACL の WCU 設計・Shield Advanced $3,000/月のコスト判断フロー・DDoS コスト補填の仕組みは CloudFront x WAF v2 x Shield 多層防御 本番運用完全ガイド で実装例を掲載しています。
▶ Git入門ハンズオン — Terraform コードで学ぶ init/commit/branch/merge 完全ガイド
– [Container本番運用 Vol1: ECS×Fargate×ECR×ECS Exec×Service Connect 完全ガイド](https://www.watchittrend.com/aws-container-production-vol1-ecs-fargate-ecr/)
– [Storage本番運用 Vol1: S3×EFS×FSx×Storage Gateway 完全ガイド](https://www.watchittrend.com/aws-storage-production-vol1-s3-efs-fsx-storage-gateway/)