Terraform で GCP のアラートを Slack 通知する

2021年2月13日

概要

やりたいこと

GCP のアラートを Slack へ通知したい。

AWS の場合 AWS Chatbot という Slack 連携サービスが存在するが、GCP にはないため、 Cloud Functions で Slack WebHook URL を叩くことにする。

アーキテクチャ

Cloud Pub/Sub でアラートとなるデータを受信し、CloudFunctions を呼び出す。

今回は Cloud Pub/Sub にメッセージが送られたとき CloudFunctions が実行される。

  • Pub/Sub -> CloudFunctions -> Slack

Terraform

Slack Incoming WebHook

通知したい Slack チャンネルの Slack WebHook URL を取得。

Slack へ通知できることを確認。

curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, World!"}' https://hooks.slack.com/services/xxxx

Slack やりとり Python

Slack 通知用 Python を作成。

vi code/main.py
import json
import urllib.request
import base64
WEB_HOOK_URL = "https://hooks.slack.com/services/xxxxx"

def handle_slack_event(event, context):
    print("""This Function was triggered by messageId {} published at {}
    """.format(context.event_id, context.timestamp))

    if 'data' in event:
        name = base64.b64decode(event['data']).decode('utf-8')
    else:
        name = 'World'
    print('Hello {}!'.format(name))

    headers = {
        "Content-Type": "application/json; charset=UTF-8"
    }
    data = {
        "text":  'Hello {}!'.format(name),
        "icon_emoji" : ":mostly_sunny:",
        "username" : "weather_news_bot"
    }

    req = urllib.request.Request(WEB_HOOK_URL, data=json.dumps(data).encode("utf-8"), method="POST", headers=headers)
    try:
        res = urllib.request.urlopen(req, timeout=5)
    except Exception as e:
        print(e)

Terraform で Pub/Sub, CloudFunctions

Terraform の準備は下記。

Pub/Sub Topic を作成する。

vi pubsub.tf
resource "google_pubsub_topic" "example" {
  name = "example-topic"

  labels = {
    foo = "bar"
  }
}

CloudFunctions を作成する。

vi cloudfunctions.tf

data "archive_file" "function_archive" {
  type        = "zip"
  source_dir  = "code" # main.pyやrequirement.txtが入ってるdir
  output_path = "code/main.zip" # zipファイルの出力パス
}

resource "google_storage_bucket" "bucket" {
  name = "test-bucket-slackbot-test"
}

resource "google_storage_bucket_object" "archive" {
  name   = "index.zip"
  bucket = google_storage_bucket.bucket.name
  source = data.archive_file.function_archive.output_path
}

resource "google_cloudfunctions_function" "function" {
  name        = "function-test"
  description = "My function"
  runtime     = "python37"

  available_memory_mb   = 128
  source_archive_bucket = google_storage_bucket.bucket.name
  source_archive_object = google_storage_bucket_object.archive.name
  event_trigger {
    event_type = "providers/cloud.pubsub/eventTypes/topic.publish"
    resource   = google_pubsub_topic.example.name
  }
  entry_point           = "handle_slack_event"
}

デプロイ。

terraform init
terraform apply

PubSub 宛にメッセージを送信し、Slack に通知が来たら成功。

gcloud pubsub topics publish example-topic --message runble1

参考

Terraform で GCP Pub/Sub トリガーのチュートリアル

Incoming Webhook の設定