AWSの請求額は、月末に請求書を見るまで気づかないことがよくあります。検証で立ち上げたリソースの消し忘れや、設定ミスによる想定外の通信量があると、気づいたときには数万円の請求になっていた、ということも起こります。
この記事では、AWS Budgetsとコスト異常検出(Cost Anomaly Detection)を使い、請求額が膨らむ前に通知を受け取る仕組みをTerraformで作ります。
2つの仕組みの違い
- AWS Budgets:あらかじめ決めた予算に対して、実績額や予測額が一定の割合を超えたら通知する
- コスト異常検出:過去の利用傾向から機械学習で「いつもと違う」支出を見つけて通知する
Budgetsは「月の合計がいくらを超えたか」を見るので、月の途中で急に増えた支出には気づきにくいことがあります。一方、コスト異常検出は「普段と比べてどうか」を見るので、予算内でも急な変化に気づけます。両方を組み合わせると、見落としが減ります。
通知先のSNSトピック
通知はSNSトピックにまとめます。Budgetsとコスト異常検出のそれぞれが、このトピックに発行できるようにポリシーを付けます。
variable "alert_email" {
type = string
}
resource "aws_sns_topic" "cost_alert" {
name = "cost-alert"
}
resource "aws_sns_topic_subscription" "email" {
topic_arn = aws_sns_topic.cost_alert.arn
protocol = "email"
endpoint = var.alert_email
}
data "aws_iam_policy_document" "cost_alert" {
statement {
actions = ["SNS:Publish"]
resources = [aws_sns_topic.cost_alert.arn]
principals {
type = "Service"
identifiers = [
"budgets.amazonaws.com",
"costalerts.amazonaws.com",
]
}
}
}
resource "aws_sns_topic_policy" "cost_alert" {
arn = aws_sns_topic.cost_alert.arn
policy = data.aws_iam_policy_document.cost_alert.json
}
- budgets.amazonaws.com:AWS Budgetsからの発行を許可する
- costalerts.amazonaws.com:コスト異常検出からの発行を許可する
メールの購読は、applyのあとに届く確認メールのリンクを押すまで有効になりません。忘れやすいので注意してください。
AWS Budgetsで月の予算を設定する
月の予算に対して、2段階で通知します。
variable "monthly_budget_usd" {
type = string
default = "100"
}
resource "aws_budgets_budget" "monthly" {
name = "monthly-cost"
budget_type = "COST"
limit_amount = var.monthly_budget_usd
limit_unit = "USD"
time_unit = "MONTHLY"
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED"
subscriber_sns_topic_arns = [aws_sns_topic.cost_alert.arn]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.cost_alert.arn]
}
}
ポイントは、2つの通知で種類を変えていることです。
- FORECASTED(予測)で80%:月末の予測額が予算の80%を超えそうになった時点で通知する。月の途中で手を打てる
- ACTUAL(実績)で100%:実際に予算を超えたら通知する。超えたことを確実に知るための通知
実績だけで通知すると、気づいた時点で予算はもう超えています。**予測の通知を入れておくと、超える前に気づけます。**ただし、予測は過去の利用実績をもとに計算されるため、使い始めたばかりのアカウントでは精度が低いことがあります。
コスト異常検出を設定する
サービスごとに支出の傾向を監視し、普段と比べて大きく増えたら通知します。
resource "aws_ce_anomaly_monitor" "service" {
name = "service-monitor"
monitor_type = "DIMENSIONAL"
monitor_dimension = "SERVICE"
}
resource "aws_ce_anomaly_subscription" "alert" {
name = "cost-anomaly-alert"
frequency = "IMMEDIATE"
monitor_arn_list = [aws_ce_anomaly_monitor.service.arn]
subscriber {
type = "SNS"
address = aws_sns_topic.cost_alert.arn
}
threshold_expression {
dimension {
key = "ANOMALY_TOTAL_IMPACT_ABSOLUTE"
match_options = ["GREATER_THAN_OR_EQUAL"]
values = ["10"]
}
}
}
- monitor_dimension = "SERVICE":EC2、RDS、NATゲートウェイなど、AWSのサービスごとに傾向を見る
- frequency = "IMMEDIATE":異常を検出したらすぐに通知する。IMMEDIATEにする場合、通知先はSNSである必要がある(メールを直接指定できるのは日次・週次のまとめ通知だけ)
- threshold_expression:想定より10USD以上多い場合だけ通知する。数十円の変動で毎回通知が来ると、通知自体を見なくなってしまう
通知の金額のしきい値は、アカウントの規模に合わせて調整してください。月数千円の検証用アカウントなら数USD、月数十万円の本番アカウントなら数十〜数百USDが目安です。
Slackに通知したい場合
メールは埋もれやすいので、チームで運用するならSlackへの通知が便利です。SNSトピックを、AWSのチャットツール連携機能(旧AWS Chatbot、現在のAmazon Q Developer in chat applications)につなぐと、Slackのチャンネルに通知できます。
ただし、Slackのワークスペースとの連携の承認は、最初にAWSのコンソールから1回だけ行う必要があります。承認が済めば、チャンネルの設定自体はTerraformで管理できます。
運用するうえでの注意点
- 請求データには遅れがある:コストのデータは即時には反映されず、数時間程度の遅れがある。通知は「数時間前までの状況」と考える
- 通知は止めてくれない:BudgetsもCost Anomaly Detectionも、通知するだけでリソースは止めない。通知を受けたら、誰が何を確認するかを決めておく
- アカウントごとに設定する:AWS Organizationsで複数アカウントを使っている場合は、管理アカウントでまとめて監視するか、各アカウントに同じモジュールを適用する
まとめ
- Budgetsは予算に対する実績・予測を、コスト異常検出は普段との違いを見る。両方を組み合わせる
- Budgetsは「予測で80%」「実績で100%」の2段階で通知すると、超える前に気づける
- コスト異常検出は通知の金額にしきい値を設け、小さな変動で通知が来ないようにする
- 通知を受けたあとの確認手順まで決めておく
一度Terraformで作っておけば、新しいアカウントにも同じ設定をすぐに適用できます。アカウントを作ったら最初に入れておきたい設定です。