9
2

More than 3 years have passed since last update.

GCP予算アラートをSlackに通知する

Last updated at Posted at 2020-06-04

目的

GCPで予算を使いすぎた(使いすぎそうになった)ときにアラートをSlackに飛ばしたい。
そのための管理コストも最小限にしたい。

通知の流れ

  1. 予算アラート ->
  2. GCP pub/sub ->
  3. GCP functions ->
  4. Slack Incoming webhook ->
  5. Slack channel

になります。こんな設定、エンジニア以外出来ないだろと行った感じですね。エンジニアがやっても面倒でした。Googleどうにかしろ。

それぞれの設定

1. 予算アラートの作成

予算が超過した場合、または、超過しそうな場合にアラートを発生させ、アカウントユーザーに対してメールを送信できます。
しかし、予算通知の場合は、トリガーの設定は反映されません。
常に1日のうちに何度も通知が実行されます。
そのため、トリガー相当の機能は通知プログラム内で実装する必要があります。
(ただし、トリガーを設定しておくと条件を満たした場合のみ後述の特定のフィールドが含まれるようになります。)

予算アラートの作成は、お支払い > 予算とアラート から行います。

GCP_budget_alert_alert.png

予算の額だけ設定しておいてください。「指定額」と「先月の使用額」を選べます。

2. GCP pub/subのトピック作成

Pub/sub consoleから、予算アラートを受け取るTopicを作成してください。
作成はトピックIDだけを入力して後はデフォルトで大丈夫です。

GCP_budget_alert_pubsub.png

作成が完了したら、先程の予算アラート設定の最下部で、先ほど作成したトピックを登録します。

GCP_budget_alert_register_pubsub.png

3. Slack incoming webhookの作成

Slackの説明に従って、通知を出したいチャンネルにIncoming webhookを設定してWebhook URLを生成してください。こちらのURLをこの後に使います。

また、Webhookには新旧のWebhookが存在します。Payloadの仕様が違います。本投稿は新しいWebhookで作成しています。

4. GCP functionsの関数作成

Pub/subからイベントを受け取り、Slackに通知を行う処理をFunctionsに作成します。

名前は任意、トリガーをCloud Pub/Subに変更し、先程作成したトピックを指定してください。ソースコードは、下載のコードで、Incoming webhookのURL部分だけを置換して、設定してください。実行する関数は”alertBudget"を指定してください。

GCP_budget_alert_create_functions.png

index.js
const { IncomingWebhook } = require("@slack/client");

/**
 * Background Cloud Function to be triggered by Pub/Sub.
 *
 * @param {object} event The Cloud Functions event.
 * @param {object} context
 */
exports.alertBudget = async (event, context) => {
  const pubsubMessage = event.data;
  const decoded = pubsubMessage.data ? Buffer.from(pubsubMessage.data, 'base64').toString() : '{}';
  const data = JSON.parse( decoded );

  // 予算をオーバーした場合はSlackに通知を投げる
  if (data.costAmount > data.budgetAmount) {
    const body = {
      "text": "GCP予算超過があります\n" + 
      `*現在の消化予算*:${data.costAmount} ${data.currencyCode}`
    };
    // こちらのURLを、各自のIncoming webhookのURLに置き換えてください。
    const webhook = new IncomingWebhook('https://hooks.slack.com/services/XXXXX');
    await webhook.send(body);
  } else {
    console.log(`${data.costAmount}/${data.budgetAmount}`);
  }

  return 'Slack notification sent successfully';

};
package.json
{
    "name": "alert-budget-http",
    "version": "0.0.1",
    "dependencies": {
        "@slack/client": "^3.15.0" 
    }
}

5. 通知のテスト

このようなJsonがPub/Subからは送られてきます。
dataに指定されている文字列は、下記のような内容がBase64でエンコードされた文字列が入っています。

RequestBodyFromPub/Sub
{
  "data": "ew0KICAgICJidWRnZXREaXNwbGF5TmFtZSI6ICJuYW1lLW9mLWJ1ZGdldCIsDQogICAgImFsZXJ0VGhyZXNob2xkRXhjZWVkZWQiOiAxLjAsDQogICAgImZvcmVjYXN0VGhyZXNob2xkRXhjZWVkZWQiOiAxLjAsDQogICAgImNvc3RBbW91bnQiOiAxMDAuMDEsDQogICAgImNvc3RJbnRlcnZhbFN0YXJ0IjogIjIwMTktMDEtMDFUMDA6MDA6MDBaIiwNCiAgICAiYnVkZ2V0QW1vdW50IjogMTAwLjAwLA0KICAgICJidWRnZXRBbW91bnRUeXBlIjogIlNQRUNJRklFRF9BTU9VTlQiLA0KICAgICJjdXJyZW5jeUNvZGUiOiAiVVNEIg0KfQ=="
}
RawDataBody
{
    "budgetDisplayName": "name-of-budget",
    "alertThresholdExceeded": 1.0,
    "forecastThresholdExceeded": 1.0,
    "costAmount": 100.01,
    "costIntervalStart": "2019-01-01T00:00:00Z",
    "budgetAmount": 100.00,
    "budgetAmountType": "SPECIFIED_AMOUNT",
    "currencyCode": "USD"
}

alertThresholdExceededはトリガーに設定している実値の閾値を超えている場合のみ含まれます。(閾値を超えていない場合は、このフィールド含まれません。)
forecastThresholdExceededはトリガーに設定している推定値を超えている場合のみに含まれます。

通知のテストを行いたい場合は、ファンクションのテストで、RequestBodyFromPub/Subの内容をコピペして「関数をテストする」を実行してください。

GCP_budget_alert_test_send.png

正しく動いていれば、Slackに次のような通知が飛びます。(文面は自分用に多少いじっています。)
GCP_budget_alert_message_sample.png

以上になりますが、長かった。。。
しかし、これ一度予算上限を超えてしまうと何度も通知されちゃうな。トリガー相当の実装は骨が折れすぎる。。。

その他みつけた実現手段

  • 旧Webhookを使ったものが比較的多くGoogle検索で引っかかります。基本的には同じなので、今回のFunctionsの実装は、旧Webhookでも動作するものになっています。
  • Googleの公式では、Slackへの通知に、Slackボットユーザーを利用しています。

参考

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2