Terraformに書いていないGCPのBilling Budgetの通知設定
はじめに
クラウドサービスの予算管理は、クラウド管理者にとって重要な業務の一つです。エンタープライズ規模なら少しの改善で大きなコスト削減になりますし、スモールビジネスの場合は文字通り身銭を切っている訳で、なるべく無駄なコストを生まないようにしたいところです。
とはいえ、クラウドサービスを利用していく中で、いつの間にか予期していなかった請求が発生することはよくあります。私も今、開発環境でGCSに謎のスキャンが不定期に走っているためコストが掛かっていて泣いています。
そんなときのためにも予算アラートを設定して、すぐに異常を検知できるようにしておくことが重要です。
GCPでも予算額に応じたアラートを設定することができ、GUIからだけではなくTerraform経由でも設定は可能です。今回はその google_billing_budget リソースで定義しようとしていましたが、通知チャンネル絡みで謎のエラーと格闘する羽目になったので、その詳細と対処法について触れたいと思います。
通知方法の分かりにくい制限
Terraformのリソースのドキュメントを読むと、all_updates_rule の monitoring_notification_channels で通知方法を指定できると書いてあります。
ではSlackに通知を送ろうということで、以下のようなコードを書きます。
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Billing Budget for ${var.project_id}"
budget_filter {
projects = ["projects/${var.project_number}"]
}
amount {
specified_amount {
currency_code = "USD"
units = var.budget_amount
}
}
threshold_rules {
threshold_percent = 1.0
}
all_updates_rule {
monitoring_notification_channels = [
google_monitoring_notification_channel.slack_channel.id,
]
}
}
resource "google_monitoring_notification_channel" "slack_channel" {
display_name = "Slack Channel"
type = "slack"
labels = {
"channel_name" = "#foobar"
}
sensitive_labels {
auth_token = var.auth_token
}
}
ただ、applyすると以下のような全くユーザーフレンドリーではないエラーが発生します。
googleapi: Error 400: Request contains an invalid argument.
途方に暮れていましたが、GUIを触っていると原因に気付きました。

Terraform側のドキュメントには書かれていませんが、メール通知しか使えないことが原因でした。
検索してもこちらのissueしか出てこなかったので、あまり知られていない制限なのかもしれません。
それでもSlackに通知を飛ばしたい
どうしてもSlack通知を飛ばしたい、という場合は方法がない訳ではありません。
pub/sub経由でcloud functionを使ってSlackに通知を飛ばす方法も巷で紹介されていますが、今ではもっとシンプルな方法もあり、
Slack側でチャンネルやDMに転送できる専用メールアドレスが生成できるので、そちらをnotification_channelsに指定すればSlackへの通知が可能になります。
多少の制約はありますが、この方法は無料版のSlackでも使用可能です。
ということで最終的なコードは以下のようになります。
resource "google_billing_budget" "budget" {
billing_account = data.google_billing_account.account.id
display_name = "Billing Budget for ${var.project_id}"
budget_filter {
projects = ["projects/${var.project_number}"]
}
amount {
specified_amount {
currency_code = "USD"
units = var.budget_amount
}
}
threshold_rules {
threshold_percent = 1.0
}
all_updates_rule {
monitoring_notification_channels = [
google_monitoring_notification_channel.slack_email.id,
]
}
}
resource "google_monitoring_notification_channel" "slack_email" {
display_name = "Slack Email"
type = "email"
labels = {
email_address = var.slack_email #念のためシークレットとして扱うのをオススメします
}
force_delete = false
}
これでSlackに通知が届くようになりました。とはいえ通知が来ないことが一番なので、来月はどうか予算内に収まりますように。。。
最後に、Tanukiの情報も是非チェックしていってください。
Discussion