7月17日、AWS Cost Explorer は推定請求額として数百万ドル、数十億ドル、一部のスクリーンショットでは数兆ドルという数字を表示した。数字は誤りで、実際に課金された人はおらず、AWS は1日以内にデータを修正した。ここで覚えておく価値があるのは、最初に異変に気づいたのが請求アラートを設定していた人たちだった、という点だ。本記事では Terraform の aws_budgets_budget を使った予算アラート設定の基礎を、単純な月次コストアラートから使用量ベースの予算、Savings Plan の利用率トラッキングまで順に解説する。

あの朝 LinkedIn や X を開いた人は、みな同じフィードを目にした。一部の国家予算より桁数の多い AWS 請求見積もりのスクリーンショットだ。前月の支払いが 0.19 ドルだったユーザーには約 25 億ドルの見積もりが表示され、最大 2.5 兆ドルという数字を投稿した人もいた。

何が起きたのか

太平洋時間の午前1時33分、AWS は Health Dashboard に、Cost Explorer が "reflecting inaccurate estimated billing data"(不正確な推定請求データを表示している)と投稿した。根本原因は AWS の言葉を借りれば "an issue with unit pricing within the estimated billing computation subsystem"(推定請求計算サブシステム内の単価に関する問題)だった。要点は次のとおり。

  • 数字は推定値であり、実際の使用量や請求額ではなかった。
  • 課金された顧客はおらず、顧客側の対応も不要だった。
  • AWS がデータをバックフィルし、7月18日には数字は正常に戻った。

興味深いのはここからだ。多くの人はこのバグを請求しきい値超過のメールで知った。アラートを設定していたアカウントは数分以内に異常を検知した。設定していなかったアカウントはソーシャルメディアで知るか、あるいは気づかないままだった。

今回は誤報だった。しかし、消し忘れた NAT Gateway、リトライループに陥った Lambda、漏洩したアクセスキーが生む請求は紛れもなく本物だ。だからこそ今週は請求アラートを整備する良い機会であり、コンソールのクリックではなくコードでやるべきだ。

なぜコンソールではなく IaC なのか

コンソールで作ったアラートは、ひとつのアカウントと誰かひとりの記憶の中にしか存在しない。Terraform なら次のようになる。

  • バージョン管理下に置かれる。誰がいつ何を変えたかが見える。
  • 新しいアカウントができたら、同じモジュールを適用して標準を維持すればよい。
  • しきい値の変更は、レビューを通るプルリクエストになる。

実際の作業を担うリソースは、AWS Budgets をラップした aws_budgets_budget だ。

1. メールアラート付きの月次コスト予算

実際の支出が 80% を超えたらメールで知らせる、月額 100 ドルの予算。

resource "aws_budgets_budget" "monthly_cost" {
  name         = "monthly-cost-budget"
  budget_type  = "COST"
  limit_amount = "100"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

2. 予測ベースの早期警告

notification_type = "FORECASTED" を使うと、月末時点の予測が予算を超過する見込みになった段階、つまりお金が実際に出ていく前に AWS が警告してくれる。ACTUAL 通知と組み合わせれば両方向をカバーできる。

resource "aws_budgets_budget" "with_forecast" {
  name         = "monthly-cost-budget"
  budget_type  = "COST"
  limit_amount = "100"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  # 予測が予算を超過しそうな場合に早期警告
  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 100
    threshold_type             = "PERCENTAGE"
    notification_type          = "FORECASTED"
    subscriber_email_addresses = ["ops@example.com"]
  }

  # 実際の支出が 90% を超えたら再度警告
  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 90
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

3. SNS 経由で Slack や PagerDuty へ

メールは埋もれる。代わりにアラートを SNS トピックへ送り、そのトピックを Slack の Webhook や PagerDuty につなぐ。

resource "aws_sns_topic" "billing_alerts" {
  name = "billing-alerts"
}

resource "aws_budgets_budget" "sns_alert" {
  name         = "monthly-cost-budget-sns"
  budget_type  = "COST"
  limit_amount = "100"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator       = "GREATER_THAN"
    threshold                 = 80
    threshold_type            = "PERCENTAGE"
    notification_type         = "ACTUAL"
    subscriber_sns_topic_arns = [aws_sns_topic.billing_alerts.arn]
  }
}

ここでの落とし穴: トピックポリシーで budgets.amazonaws.com サービスプリンシパルに SNS:Publish を許可しておく必要がある。これがないと Budgets は配信できず、アラートは音もなく消える。予算側にはエラーが出ない。

4. サービス単位の予算

特定のサービス、たとえば EC2 だけを監視するには cost_filter を追加する。

resource "aws_budgets_budget" "ec2_only" {
  name         = "ec2-monthly-budget"
  budget_type  = "COST"
  limit_amount = "50"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  cost_filter {
    name   = "Service"
    values = ["Amazon Elastic Compute Cloud - Compute"]
  }

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

5. 使用量予算: S3 を 3 GB まで

FinOps の仕事はドルの追跡だけではない。消費量の追跡もその一部だ。budget_type = "USAGE" を使うと、予算を通貨ではなく使用量の単位で定義できる。S3 ストレージを 3 GB に抑える予算は次のとおり。

resource "aws_budgets_budget" "s3" {
  name         = "s3-3GB-limit"
  budget_type  = "USAGE"
  limit_amount = "3"
  limit_unit   = "GB"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

無料枠に収めたい個人プロジェクトや、「なぜこのバケットは増え続けているのか」を請求明細の項目になる前に捕まえる用途に向いている。

6. Savings Plan 利用率の予算

FinOps のもう半分。使いすぎを捕まえることは大事だが、前払いした割引を無駄にしないことも同じくらい大事だ。Savings Plan を購入したのに利用率が低ければ、ワークロードが別の場所でオンデマンドで動いている間、コミットメントはお金を燃やし続けている。SAVINGS_PLANS_UTILIZATION 予算タイプはまさにそれを追跡する。

resource "aws_budgets_budget" "savings_plan_utilization" {
  name         = "savings-plan-utilization"
  budget_type  = "SAVINGS_PLANS_UTILIZATION"
  limit_amount = "100.0"
  limit_unit   = "PERCENTAGE"
  time_unit    = "MONTHLY"

  cost_types {
    include_credit             = false
    include_discount           = false
    include_other_subscription = false
    include_recurring          = false
    include_refund             = false
    include_subscription       = true
    include_support            = false
    include_tax                = false
    include_upfront            = false
    use_blended                = false
  }

  notification {
    comparison_operator        = "LESS_THAN"
    threshold                  = 90
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["finops@example.com"]
  }
}

演算子が逆向きになっている点に注意。comparison_operator = "LESS_THAN" だ。このアラートは支出が増えたときではなく、利用率が 90% を下回ったときに発火する。同じパターンは RI_UTILIZATION を使って Reserved Instance にも適用できる。

まとめ

7月17日の兆ドル級スクリーンショットは表示上のバグだった。誰もその金額を払っておらず、AWS は1日以内にデータを修正した。それでも教訓は変わらない。請求の異常は、タイムラインではなく自分のアラート経由で届くべきだ。

  • aws_budgets_budget で月次予算を定義する。
  • FORECASTEDACTUAL の通知を組み合わせて二段構えの警告にする。
  • アラートは SNS 経由で、チームが実際に見ているチャンネルへ流す。
  • 使用量予算(S3 の 3 GB)と Savings Plan 利用率のトラッキングで全体像を仕上げる。

次に「AWS の請求額が爆発した」がトレンド入りしたら、コーヒー片手に眺めていればいい。今回のインシデントの背景は The RegisterTechCrunch が発生当時から報じている。

次に読む

参考資料