😸

GCPのコスト(予算)アラートをCloudfunctionsを使って、Slackに通知してみた(Terraform)

2023/11/09に公開

記事の内容

GCPのコストアラート(予算設定)をSlackに通知する方法を紹介します。(Terraformを利用します。)

記事を読むと得られるもの

  • GCPのコストアラートの実装方法
  • TerraformでCloudFunctionsを作成する方法

対象読者

  • GCP利用者

記事の長さ

2分で読めます

Cost Alertを設定する

main.tf

resource "google_billing_budget" "this" {
  billing_account = var.billing_account
  display_name    = "Monthly Cost"
  budget_filter {
    credit_types_treatment = "INCLUDE_ALL_CREDITS"
    projects               = ["projects/${var.project_number}"]
  }

  amount {
    specified_amount {
      units = "100"
    }
  }

  threshold_rules {
    threshold_percent = 0.5
  }

  threshold_rules {
    threshold_percent = 1.0
  }
}

上記Terraformファイルにて、予算アラートを作成できます。

Pub/Subを予算アラートに設定する

次に、アラートの上限に使用額が達した際にトリガーされるPub/Subを作成して、それを予算アラートに紐づけます。
先ほど作成したmain.tfファイルを以下のように変更して、Terraform applyを実行してください。

main.tf

resource "google_billing_budget" "this" {
  billing_account = var.billing_account
  display_name    = "Monthly Cost"
  budget_filter {
    credit_types_treatment = "INCLUDE_ALL_CREDITS"
    projects               = ["projects/${var.project_number}"]
  }

  amount {
    specified_amount {
      units = "100"
    }
  }

  threshold_rules {
    threshold_percent = 0.5
  }

  threshold_rules {
    threshold_percent = 1.0
  }

  all_updates_rule {
    pubsub_topic = "projects/${var.project_id}/topics/${google_pubsub_topic.this.name}"
  }

  depends_on = [
    google_pubsub_topic.this
  ]
}

resource "google_pubsub_topic" "this" {
  project = var.project_id
  name    = "billing-alerts"
}

Slack Appを作成する

次に、Slackに対して、通知を行うためにSlack Appを作成します。

https://api.slack.com/apps

こちらのURLにアクセスして、Create New Appから、Slack通知を行いたいWorkspaceに対して、Slack Appを作成してください。

Slack上で、Slack Appを追加する

Slack Appの作成が完了したら、通知を行いたいSlackチャンネルをSlackのアプリケーションで開き、Integrationsタブから、今作成してSlack AppをSlackチャンネルに追加してください。

OAuthにチャット書き込みの権限を付与する

Slack Appの作成とSlackチャンネルへの追加が完了したら、そのSlack Appの管理画面のサイドバーからOAuth & Permissionsを選択し、Add an OAuth Scope ボタンをクリックし、chat:write を選択します。

これで、OAuth Tokenを使った外部アプリケーションからSlackへの書き込みが可能になります。

Oauth Tokenを取得する

Slack Appの作成とSlackチャンネルへの追加が完了したら、そのSlack Appの管理画面のサイドバーからOAuth & Permissionsを選択し、Bot User OAuth Tokenの値をコピーします。(xoxb-から始まる文字列です)

このTokenを利用して、CloudFunctionsからSlackに通知を行うため、どこかにメモしておいてください。

Cloud Functionsを作成する

Pub/Subから通知を受け取り、Slackにメッセージを送るCloudFunctionsを作成します。

CloudFunctions上で動作するnode.jsのファイルを作成する

Cloud Functionsでは、PythonやNodejsなど、さまざまなプログラミング言語が動作します。
今回は、node.jsを使って、Cost Alertの通知をSlackにPOSTするプログラムを書きます。

index.js

const slack = require('slack');

const BOT_ACCESS_TOKEN = process.env.BOT_ACCESS_TOKEN || '';
const CHANNEL = process.env.SLACK_CHANNEL || '';

exports.notifySlack = async pubsubEvent => {
  const pubsubAttrs = pubsubEvent.attributes;
  const pubsubData = Buffer.from(pubsubEvent.data, 'base64').toString();

  if (pubsubData.costAmount > pubsubData.budgetAmount) {
    await slack.chat.postMessage({
      token: BOT_ACCESS_TOKEN,
      channel: CHANNEL,
      text: `The cost of ${pubsubData.budgetDisplayName} has exceeded the budget`,
    });
    return 'Slack notification sent successfully';
  } else {
    return 'The cost is within the budget range';
  }
};

package.json

{
  "name": "cloud-functions-billing",
  "private": "true",
  "version": "0.0.1",
  "description": "Examples of integrating Cloud Functions with billing",
  "main": "index.js",
  "engines": {
    "node": ">=16.0.0"
  },
  "dependencies": {
    "slack": "^11.0.1"
  }
}

※参考 ( https://cloud.google.com/billing/docs/how-to/notify#write-a-cloud-function )

TerraformでCloud Functionsを作成する

先ほど作成したnode.jsのファイルが動作するCloudFucntionsをTerraformで作成します。

cf.tf

data "archive_file" "this" {
  type        = "zip"
  source_dir  = "./sources"
  output_path = "./sources/functions.zip"
}

resource "google_storage_bucket" "this" {
  project = var.project_id
  name          = "my-bucket-for-test-cost-alert"
  location      = "ASIA"
  storage_class = "STANDARD"
}

resource "google_storage_bucket_object" "this" {
  name   = "packages/functions.${data.archive_file.this.output_md5}.zip"
  bucket = google_storage_bucket.this.name
  source = data.archive_file.this.output_path
}

resource "google_cloudfunctions_function" "this" {
  project = var.project_id
  name                  = "cost-alert"
  runtime               = "nodejs18"
  source_archive_bucket = google_storage_bucket.this.name
  source_archive_object = google_storage_bucket_object.this.name
  available_memory_mb   = 256
  event_trigger {
    event_type = "providers/cloud.pubsub/eventTypes/topic.publish"
    resource   = google_pubsub_topic.this.name
  }
  entry_point           = "notifySlack"

  environment_variables = {
    BOT_ACCESS_TOKEN = "<BOT Tokenを入力>"
    SLACK_CHANNEL = "<通知したいチャンネル名を入力>"
  }
}

※BOT TOEKNとSLACK CHANNELを、編集してください(SecretManager等を使った方がいいのですが、今回は割愛します。)

上記、Terraformファイルを実行すると、sourcesディレクトリ配下に配置したnode.jsが稼働するCloudFunctionsが作成されます。

完成

以上でCostAlertをSlackに通知する、Pub/SubとCloudFunctionsが作成できました。

note

勉強法やキャリア構築法など、エンジニアに役立つ記事をnoteで配信しています。

https://note.com/ring_belle/membership

Discussion