notebook

都内でWEB系エンジニアやってます。

CloudMonitoringでアラートを作成しSlackへ通知する

GCPでの通知でSlackが連携先として追加できるようになったみたいなのでちょっと触ってみるためにCloudMonitoringと合わせて使ってみた

流れ

やることは以下

  • 通知先の設定
    • GUIでSlack連携の設定
    • terraform import
  • Alert Policyの設定
    • Monitoring指標の設定
      • GUIで設定してみる
    • Terraformで書く

通知先の設定

GUIでSlack連携の設定

通知チャネルの管理  |  Cloud Monitoring  |  Google Cloud

cloud.google.com

上記みながら手動で追加

  • Slack連携

f:id:swfz:20210917123232p:plain

  • チャンネル設定

f:id:swfz:20210917123238p:plain

  • テスト送信してみた

f:id:swfz:20210917123243p:plain

terraform import

  • 通知チャンネルリストの取得
$ gcloud alpha monitoring channels list
---
creationRecord:
  mutateTime: '2021-09-14T18:10:25.581971797Z'
displayName: DevNotification
enabled: true
labels:
  auth_token: '****************************************************Zlw7'
  channel_name: '#dev-notification'
mutationRecords:
- mutateTime: '2021-09-14T18:10:25.581971797Z'
name: projects/sample-project-111111/notificationChannels/1111111111111111111
type: slack

monitoring_notification_channelの書き方

ドキュメント読めば良さそう

google_monitoring_notification_channel | Resources | hashicorp/google | Terraform Registry

https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_notification_channelregistry.terraform.io

importする

  • import時の書き方
$ terraform import google_monitoring_notification_channel.default {{name}}

listで取得したnameをimoprt時に記述する

事前にgoogle_monitoring_notification_channel.defaultの枠だけtfファイルに記述して用意しておく必要がある

  • importコマンドを実行する
$ terraform import google_monitoring_notification_channel.default projects/sample-project-111111/notificationChannels/1111111111111111111
google_monitoring_notification_channel.default: Importing from ID "projects/sample-project-111111/notificationChannels/1111111111111111111"...
google_monitoring_notification_channel.default: Import prepared!
  Prepared google_monitoring_notification_channel for import
google_monitoring_notification_channel.default: Refreshing state... [id=projects/sample-project-111111/notificationChannels/1111111111111111111]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
  • importしたstateを見ながら設定を移す
$ terraform state show -state=terraform.tfstate google_monitoring_notification_channel.default
# google_monitoring_notification_channel.default:
resource "google_monitoring_notification_channel" "default" {
    display_name = "DevNotification"
    enabled      = true
    id           = "projects/sample-project-111111/notificationChannels/1111111111111111111"
    labels       = {
        "auth_token"   = ""
        "channel_name" = "#dev-notification"
    }
    name         = "projects/sample-project-111111/notificationChannels/1111111111111111111"
    project      = "sample-project-111111"
    type         = "slack"
    user_labels  = {}

    timeouts {}
}

余談だが出力されたものそのまま貼り付けてapplyしたらエラーが出た

id,nameはいらないみたい

╷
│ Error: Invalid or unknown key
│
│   with google_monitoring_notification_channel.default,
│   on notification.tf line 4, in resource "google_monitoring_notification_channel" "default":
│    4:     id           = "projects/sample-project-111111/notificationChannels/1111111111111111111"
│
╵
╷
│ Error: Computed attributes cannot be set
│
│   with google_monitoring_notification_channel.default,
│   on notification.tf line 9, in resource "google_monitoring_notification_channel" "default":
│    9:     name         = "projects/sample-project-111111/notificationChannels/1111111111111111111"
│
│ Computed attributes cannot be set, but a value was set for "name".
╵

最終的なtfファイルは次のようになった

  • notification.tf
resource "google_monitoring_notification_channel" "default" {
    display_name = "DevNotification"
    enabled      = true
    labels       = {
        "auth_token"   = ""
        "channel_name" = "#dev-notification"
    }
    project      = data.google_client_config.current.project
    type         = "slack"
    user_labels  = {}

    timeouts {}
}

Alert Policyの設定

今回は適当なWorkflowsを作っていくつかログを流すようにしてそれを検知できるようにする

Workflowの内容は割愛する

monitoring alert policy

次のページを見ながら設定する

google_monitoring_alert_policy | Resources | hashicorp/google | Terraform Registry

https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_alert_policyregistry.terraform.io

変更が結構ありそうなのはConditionの中かな

ログベースと指標ベースのアラートポリシー

Monitoring API のアラート ポリシー  |  Google Cloud

cloud.google.com

アラートポリシーにはログベースと指標ベース2種類ある

Add support for 'conditionMatchedLog' block in google_monitoring_alert_policy · Issue #9893 · hashicorp/terraform-provider-google

github.com

本当はログベースを使いたかったが上記Issueにあるようにログベースのアラート用のフィルタはまだterraformのgoogle providerが対応できていない模様

ログベースは手動で試したが現時点で特に書けそうなことがないので通知した時点のキャプチャだけ載せておく

f:id:swfz:20210917123248p:plain

指標ベースでやってみる

指標ベースの中には条件タイプ(condition)がいくつかある

  • MetricAbsence
  • MetricThreshold
  • MonitoringQueryLanguageCondition

今回はMetricThresholdを使う

Metrics ExplorerでMetricsを作ってみる

どうにもfilterの内容がよくわからなかったのでGUIで実際に作ってみてクエリを参考にする

GUIのMetrics ExplorerでMetricsを作成後JSONで定義を参照できるボタンがあるのでそれで見てみる

  • 設定画面

f:id:swfz:20210917123254p:plain

  • 参照ボタン

f:id:swfz:20210917123300p:plain

中身はこんな感じ

{
  "dataSets": [
    {
      "timeSeriesFilter": {
        "filter": "metric.type=\"logging.googleapis.com/log_entry_count\" resource.type=\"workflows.googleapis.com/Workflow\" metric.label.\"severity\"=\"WARNING\"",
        "minAlignmentPeriod": "60s",
        "aggregations": [
          {
            "perSeriesAligner": "ALIGN_RATE",
            "crossSeriesReducer": "REDUCE_NONE",
            "groupByFields": []
          },
          {
            "perSeriesAligner": "ALIGN_NONE",
            "crossSeriesReducer": "REDUCE_NONE",
            "groupByFields": []
          }
        ]
      },
      "targetAxis": "Y1",
      "plotType": "LINE"
    }
  ],
  "options": {
    "mode": "COLOR"
  },
  "constantLines": [],
  "timeshiftDuration": "0s",
  "y1Axis": {
    "label": "y1Axis",
    "scale": "LINEAR"
  }
}

なるほど!

あとから調べてみると次のドキュメントを読めば良さそう

モニタリング フィルタ  |  Cloud Monitoring  |  Google Cloud

cloud.google.com

terraformで書いてみる

で、今度はそれをTerraformの定義に落とし込む

  • alert.tf
resource "google_monitoring_alert_policy" "sample" {
  display_name = "My Alert Policy"
  combiner     = "OR"
  conditions {
    display_name = "test condition"
    condition_threshold {
      filter          = "metric.type=\"logging.googleapis.com/log_entry_count\" resource.type=\"workflows.googleapis.com/Workflow\" metric.label.\"severity\"=\"WARNING\""
      duration        = "60s"
      comparison      = "COMPARISON_GT"
      threshold_value = 1
    }
  }

  notification_channels = [
    google_monitoring_notification_channel.default.id
  ]
}

threshold_valueは指定しないと0が閾値になる

notification_channelsにアラートの通知先のIDを入れる(今回はSlack)

これでapplyしてサンプルのWorkflowを実行してみた

f:id:swfz:20210917123306p:plain

しっかりSlackに通知が来た

durationが60sなので一瞬で回復したという判断をされたようだがこの辺は実際の要件に合わせて設定すれば良い

これで、Loggingから集計した結果をもとにアラートをSlack経由で通知するということが実現できた

この手法ではログの細かな内容までは閲覧できないので問題が発生した場合はLoggingなりでログを見に行く必要がある

特定のログがこのくらい以上いったらまずいので通知したいみたいなときには使えそう

  • おまけ

f:id:swfz:20210917123311p:plain

まとめ

  • Cloud Monitoringで指標ベースのポリシーを設定しSlack通知まで行った
  • terraform import初めて使ったけど思ったより楽だった
    • terraform上では1リソースだがAPIとのマッピングでは複数だったりネストする場合はリソースIDだけが表示されてうまくimportできなそうだったので今後調べたい
  • Terraformによるログベースのアラートポリシー作成は執筆時時点では行えない
  • モニタリングフィルタをサクッと書けるようになるの結構時間かかりそうな気がした
    • 条件によっても書き方が変わりそうなのでぱっと切り替える頭になりづらそう
    • この辺知らずにやって大分怒られた
  • 調べている間にログベースの通知コンテンツ内容に変数を含められることがわかったので別途試してみる

今回使ったterraformのファイルは次のリポジトリに置いた

terraform-sample/google/logging-alert-notification at master · swfz/terraform-sample

github.com