😸

DatadogのSlackへの通知をTerraformで管理することで「アラート設定ぐちゃぐちゃなんだけど...」を撲滅する

2021/12/06に公開

こんにちは、株式会社オプティマインドの戸ヶ里です。
本記事はOPTIMIND x Acompany Advent Calendar 2021の12日目の記事となります。

私事ですが、12月12日が誕生日なので❤️していただけると非常に喜びます。

本記事のスコープ

TerraformでDatadog Monitorを作成して、Slackにアラート通知をします。
簡易的にするためにローカルでTerraformを実行します。


スコープ外

解決したい課題

日々、サービスを運用をしている中でアラートやモニタリングの変更が発生することがあります。
変更が重なると、
・なんでこうなっているんだっけ?
・いつ誰が変えたんだろう?
・同じような監視なんだけど、閾値が少しだけ差異がある?
・そもそもこの監視なに?
といったことが起きると思います。

この時に前任者が既にいなかったりするとそれはそれは大変ですよね。
DatadogもTerraformで管理することで、
誰がいつどんな理由で変更したのか履歴を残すことができるようになります。
厳密にはTerraformによる管理というよりはgitなどのバージョン管理ツールによる賜物ですが気にしないでください。

また、コードで管理することでイミュータブルにできるので度重なる変更や新たなサービスの監視を設定するときのミスの低減や集中力の温存(SREも人間なので生産性に割と効いてくる)ができます。

デメリット(コード管理が必要ない状況もある。)

全てのチームやサービスでコード管理するべきとは思いません。
デメリットとして、
・GUIでぽちぽちするより習得コストが高い。
・構築の工数がかかる。
ため、特にスタートアップなどの一刻でも早くMVPを出して市場の反応を見たい場合には時間の無駄だと思います。

加えて、AWSなどのサーバーリソースと異なり、後からコード管理に変更することは比較的容易ですので安心してください。
既存の設定をTerraformの形式にimportできるOSSも存在しております。
参考記事:
https://engineering.mercari.com/en/blog/entry/2019-12-09-122134/

やり方

では、実際に構築していきましょう。今回は以下のフローで進めていきます。

1. SlackとDatadogを連携
2. 阿部寛さんのHPをGETするDatadog Monitorを作成
3. 動作確認

※非常に軽量であるため阿部寛さんのHPを利用させていただきました。もし、この記事を参考に構築される場合は阿部寛さんにご迷惑がかからないようお願いいたします。

0. 使用ツール

% terraform -v
Terraform v1.0.11
on darwin_amd64
デバイス:mac OS Catalina
Slack WorkSpace名:Optimind
Slack チャンネル名:togari_book

1. SlackとDatadogを連携

まずはDatadogからSlackに通知をするために、SlackとDatadogを連携しましょう。
Datadog→Integrations→Slackから"Connect Slack Account"をクリックします。


SlackとDatadogを連携を許可します。
本記事では、私が所属しているオプティマインドのスラックと連携します。


連携が完了しますと、先ほどはなかったAccount: Optimindが追加されていることがわかります。
Add Channelをクリックして、通知したいチャンネルを追加します。本記事では#togari_bookを追加しました。


以上でSlackとDatadogを連携は完了です。

2. 阿部寛さんのHPをGETするDatadog Monitorを作成

阿部寛さんのHPをGETして、レスポンスのステータスコードが200ならば問題なし、200以外ならばSlackに通知するシンセティックテストを作ります。

※シンセティックテスト:合成テストや外形テストと呼ばれる。語弊を恐れずにいうと、GETなどのレスポンスを確認するテストなので外形テストが理解しやすいと思う。

DatadogでOrganization Settingsからapi_key(API Key), app_key(Application Key)を作成します。
https://docs.datadoghq.com/ja/account_management/api-app-keys/
好きなディレクトリにmonitor.tfを作成します。誤操作を防ぐために空のディレクトリが良いと思います。

monitor.tf
terraform {
  required_providers {
    datadog = {
      source = "DataDog/datadog"
    }
  }
}

# Configure the Datadog provider
# api_key, app_keyを入れてください
# 実際に運用するときは変数化しましょう
provider "datadog" {
  api_key = "xxx"
  app_key = "yyy"
}

resource "datadog_synthetics_test" "access_check_to_abe_hiroshi" {
  name = "阿部寛さんのサイトにアクセス"
  type = "api"
  locations = ["aws:ap-northeast-1"]
  status          = "live"
  subtype         = "http"
  options_list {
    accept_self_signed   = false
    allow_insecure       = false
    follow_redirects     = false
    min_failure_duration = 0
    min_location_failed  = 1
    tick_every           = 900
  }
  request_definition {
    method = "GET"
    url    = "http://abehiroshi.la.coocan.jp/"
  }

  assertion {
    operator = "is"
    target   = "200"
    type     = "statusCode"
  }

# スラックに通知するの場合は、@slack-[Workspace名]-[チャンネル名]となっております
message = <<EOF
{{#is_alert}} 障害を検知しました {{/is_alert}}
{{^is_alert}} 復旧しました {{/is_alert}} 

@slack-Optimind-togari_book
EOF
}

monitor.tfが存在するディレクトリで以下のコマンドを実行します。

% terraform init
% terraform apply

# terraform apply の前に terraform planを実行するとDry runができるため
# 安全に既存リソースとの差分の確認が行えます。

Datadog→Monitor で確認するとSynthetic Testが作成されていることが確認できます。
(厳密にはMonitorとSynthetic Testは違うのですが今回は割愛)


3. 動作確認

今回は以下の方法で動作確認をします。

3.1. 間違ったURLにGETをするTestをアプライする。
3.2. アラートがSlackに通知されることを確認する。

3.1. 間違ったURLにGETをするTestをアプライする。

GETできないURLに変更します。
余談ですが、差分にシンタックスハイライトをつけられる機能めちゃくちゃ見やすいですね。

monitor.tf
terraform {
  required_providers {
    datadog = {
      source = "DataDog/datadog"
    }
  }
}

# Configure the Datadog provider
# 実際に運用するときは変数化しましょう
provider "datadog" {
  api_key = "xxx"
  app_key = "yyy"
}

resource "datadog_synthetics_test" "access_check_to_abe_hiroshi" {
  name = "阿部寛さんのサイトにアクセス"
  type = "api"
  locations = ["aws:ap-northeast-1"]
  status          = "live"
  subtype         = "http"
  options_list {
    accept_self_signed   = false
    allow_insecure       = false
    follow_redirects     = false
    min_failure_duration = 0
    min_location_failed  = 1
    tick_every           = 900
  }
  request_definition {
    method = "GET"
+    url    = "http://404.abehiroshi.la.coocan.jp/"
-    url    = "http://abehiroshi.la.coocan.jp/"
  }

  assertion {
    operator = "is"
    target   = "200"
    type     = "statusCode"
  }

message = <<EOF
{{#is_alert}} 障害を検知しました {{/is_alert}}
{{^is_alert}} 復旧しました {{/is_alert}} 

@slack-Optimind-togari_book
EOF
}

3.2. アラートがSlackに通知されることを確認する。

Slackを確認してみるとアラートが通知されていることが確認できました。


最後に

最後までご拝読いただきましてまことにありがとうございました。
実際に運用するとしたら、今回はスコープ外としたGitOpsが必須になります。また、tfstateをどこに置くかなど検討すべきことはまだまだありますが、本記事がその前段階の触りになりましたら嬉しく思います。

不明点等ございましたらコメントお待ちしております。

それでは良い開発者ライフを!

Discussion