ノーコードだとメールしか通知設定ができない
Cloud Monitoringの通知にWebhookやSlackがあるので、Slackに通知するのはポチポチするだけでできるだろう…と思ったが、出来ない。
未来は出来るようになっているかもしれないが、今(2025/06/28)はまだできない。
仕方がないのでPub/SubからCloud Run FunctionsをコールしてもらってSlackに通知してもらうようにする。
アラートの設定にPub/Subトピックスを追加する
Google Cloudにログインをしてから
- 「課金」→「予算とアラート」を選択します。
- 「予算の作成」を開き、予算の名前、対象のプロジェクト、期間、金額などを設定します。
- 次に、アラートのしきい値を設定します。例えば、「実際の費用の50%」「90%」「100%」などに設定します。
- 「通知の管理」セクションをみるとわかるのですが、メールしか出来ないです。「Pub/Subトピックをこの予算に接続する」 にチェックを入れます。
そして、新しいPub/Subトピックを作成するか、既存のトピックを選択します。このトピックに予算アラートのメッセージが送信されます。
Slack Incoming Webhooksの設定をする
ここは割愛します。
Cloud Run Functionsの作成をする
-
Google Cloud Consoleから、「pub/sub」を選択します。
-
トリガータイプ: 「Cloud Pub/Sub」を選択します。
-
Pub/Subトピック: ステップ1で作成した予算アラートのPub/Subトピックを選択します。(例えばbuget_alertという場合)
-
ランタイム: 「Python 3.x」のいずれかを選択するのですが…3.1.13でやったら何故かうまくいかず。 3.1.12でやったらうまくいきました。
-
エントリポイント: 関数名を入力します (例:
process_budget_alert
)。 -
コード: 以下のサンプルコードを参考に、
main.py
とrequirements.txt
を設定します。
main.py
import base64
import json
import os
import requests
# from datetime import datetime # 必要であればコメント解除
def process_budget_alert(event, context):
"""
Pub/Sub からの予算アラートメッセージを処理し、Slack に通知します。
Args:
event (dict): The Pub/Sub message.
context (google.cloud.functions.Context): The Cloud Functions event metadata.
"""
try:
if 'data' in event:
message_data = base64.b64decode(event['data']).decode('utf-8')
budget_alert = json.loads(message_data)
else:
raise ValueError("No data found in Pub/Sub event.")
print(f"Received budget alert: {budget_alert}")
slack_webhook_url = os.environ.get('SLACK_WEBHOOK_URL')
if not slack_webhook_url:
raise ValueError("SLACK_WEBHOOK_URL environment variable is not set.")
budget_display_name = budget_alert.get('budgetDisplayName', '不明な予算')
cost_amount = budget_alert.get('costAmount', 0.0)
cost_interval_start = budget_alert.get('costIntervalStart', '')
alert_threshold_exceeded = budget_alert.get('alertThresholdExceeded', 0.0)
currency = budget_alert.get('currencyCode', 'JPY')
formatted_date = ""
if cost_interval_start:
try:
from datetime import datetime # ここでインポート
dt_object = datetime.fromisoformat(cost_interval_start.replace('Z', '+00:00'))
formatted_date = dt_object.strftime("%Y年%m月%d日")
except ValueError:
formatted_date = cost_interval_start
slack_message_text = f"*Google Cloud 予算アラート: {budget_display_name}*"
slack_message_text += f"\n- *使用金額*: {currency} {cost_amount:,.2f}"
slack_message_text += f"\n- *期間開始日*: {formatted_date}"
slack_message_text += f"\n- *アラートしきい値*: {alert_threshold_exceeded * 100:.0f}% を超過しました。"
slack_payload = {
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": slack_message_text
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "詳細はGoogle Cloud Consoleをご確認ください。"
}
]
}
]
}
response = requests.post(
slack_webhook_url, data=json.dumps(slack_payload),
headers={'Content-Type': 'application/json'}
)
response.raise_for_status()
print("Slack notification sent successfully.")
except Exception as e:
print(f"Error processing budget alert: {e}")
requirement.txt
functions-framework==3.*
requests
-
ランタイム環境変数
SLACK_WEBHOOK_URLを忘れずに設定する。
テストしてみる
Cloud Run Functionsのテストからペイロードを送ることも出来るのですが、せっかくなので、Pub/Subからやってみます。
-
「メッセージの本文」を以下のようにしてメッセージを送ります。
{ "budgetDisplayName": "あなたのプロジェクトの予算名 (例: 月額10000円予算)", "costAmount": 5500.75, "costIntervalStart": "2025-06-01T00:00:00Z", "costIntervalEnd": "2025-07-01T00:00:00Z", "alertThresholdExceeded": 0.5, "forecastAmount": 9000.00, "forecastThresholdExceeded": 0.9, "currencyCode": "JPY", "gcpProjectId": "your-gcp-project-id" }
動かしてみて…
Pub/Subの通知はしきい値に達してから来ると思ってたのですが、そうではありませんでした。
一日に何度も通知がきます。
そして、それは仕様で、ちゃんと公式サイトに記載されています。
なので、しきい値を超えると何度もSlackに通知します。
そうなったらPub/Subへの通知を辞めるか、プログラムで一日1回だけSlackに送るように変更するしか無いですね。
問題点
問題点1
理由がまだよくわかっていないのですが、ここに書いてある手順のとおりにPub/Sub→トリガーの設定から作らないと出来ない。
Cloud Run Functionsから作ると、何故かトリガータイプがHTTP(S)になってしまう。
問題点2
Pub/Subの通知が一日に何度も来る。30分に一回の割合で来るので、個人で行っているGoogle Cloud だと、無料枠を超えてしまうかもしれない。
などなどと考えると、メール通知でいいのかなぁ…と思ってしまいますね。