- バックエンド
- PdM
- CS職のオープンポジション募集
- 他30件の職種
- 開発
- ビジネス
- その他
この記事は Datadog Advent Calendar 2025 の 19 日目の記事です。
こんにちは、Infra Squad の @fohte です。
ウォンテッドリーでは、システムのオブザーバビリティを支える基盤として Datadog を全面的に活用しています。Datadog の機能の中でも Monitor はとりわけサービスの信頼性を担保する上で重要です。この重要な設定を Terraform で管理したいという思いが生まれるのは自然かもしれませんが、これを実現するにはいくつかの難しさがあり、ウォンテッドリーでは長らく Monitor が手動で管理されていました。
最近になって、レビュープロセスを通したいケースが増えてきたこともあり、徐々に Terraform で管理された Monitor が増えてきています。本記事では、Web UI と Terraform を共存させる現実的なアプローチについて紹介します。
目次
なぜ Terraform で管理するのか
コード化による変更履歴の可視化と、コードレビュープロセスの導入
同じパターンの Monitor を効率的に管理する
アラートメッセージに Runbook を埋め込む
CI によるバリデーションで設定ミスを防止できる
Monitor の Terraform 管理の難しさ
Web UI の利便性
すべてを Terraform 化する必要はない
Web UI から Terraform への移行
Export to Terraform 機能の活用
生成 AI エージェントの活用
Terraform 管理されている Monitor を判別できるようにする
タグ付けを CI で検証する
最後に
なぜ Terraform で管理するのか
Terraform で管理するメリットはいくつかありますが、特に次の 4 点が大きいと考えています。
- コード化による変更履歴の可視化と、コードレビュープロセスの導入
- 同じパターンの Monitor を効率的に管理する
- アラートメッセージに埋め込んだ Runbook をレビューできる
- CI によるバリデーションで設定ミスを防止できる
コード化による変更履歴の可視化と、コードレビュープロセスの導入
Monitor の設定変更を Pull Request で行うことで、変更内容を他のメンバーがレビューできるようになります。なぜこの閾値にしたのか、この通知先で正しいのか、といった議論が履歴として残り、後から経緯を追いやすくなります。
また、Datadog の Web UI 上でも変更履歴は確認できますが、変更の意図までは記録されません。Terraform で管理することで、コミットメッセージや Pull Request の description に変更理由を残せます。さらに、コード内にコメントを書くことで「この閾値は過去の障害事例から導いた値」「この通知先は SRE チーム用」といった設定の意図を直接残すこともできます。
同じパターンの Monitor を効率的に管理する
たとえばサービスごとにエラー率の閾値や通知先を変えたい場合、service:* のようなワイルドカードでは全サービス共通の設定しかできません。この workaround として、Terraform の for_each を使うことで共通化しつつサービスごとに異なる設定の Monitor を管理しています。
locals {
service_monitors = {
"service-a" = { critical = 10, warning = 5 },
"service-b" = { critical = 3, warning = 1 },
"service-c" = { critical = 15, warning = 10 },
}
}
resource "datadog_monitor" "service_error_rate" {
for_each = local.service_monitors
name = "High error rate [${each.key}]"
type = "query alert"
query = "min(last_5m):avg:trace.http.errors{service:${each.key}}.as_rate() > ${each.value.critical}"
tags = concat(local.default_tags, ["service:${each.key}"])
}新しいサービスを追加するときは locals にエントリを追加するだけで済み、閾値の一括変更も容易です。
ただし、これは前述したように workaround です。同じようなパターンの Monitor が複数作成されるため、Web UI 上では一覧が見づらくなる欠点があります。
Terraform 管理することでこういった抽象化や共通化が可能になるのも、コード化の大きなメリットのひとつです。
アラートメッセージに Runbook を埋め込む
ウォンテッドリーでは、監視に対応する手順をまとめた Runbook を専用リポジトリを用意し一元管理しています。一方で、特定の Monitor に 1 対 1 で対応するような手順は Monitor メッセージ内に直接記述し、アラートを見た瞬間に手順がわかるようにしています。
たとえば特定のインフラ障害を検知する Monitor では、その Monitor 専用の対応手順をメッセージに埋め込んでいます。
message = <<-EOT
{{#is_alert}} @slack-war_room {{/is_alert}}
サービス ${each.key} のエラー率が上昇しています。
■ Runbook
1. Datadog APM でエラーログ (env:production) の傾向を確認する
2. 最近のデプロイメントパイプラインを確認する
3. [詳細な共通手順はこちら](https://github.com/example/runbooks/blob/main/common/apm-error.md)
EOTTerraform で管理することで、Runbook のアップデートもコードレビューの対象になります。アラートは飛んできたが手順が古くて役に立たない、という事態を防ぎやすくなります。
CI によるバリデーションで設定ミスを防止できる
Terraform で管理することで、CI でバリデーションを自動実行できるようになるなど静的検査が実現できるようになります。
ウォンテッドリーでは、後述するようにタグの付け忘れを CI で検出しています。まだウォンテッドリーではこれ以外の用途はありませんが、たとえば他にも非推奨メトリクスの使用検出や命名規則の統一など、運用上のルールをポリシーとして定義しておきたいときに便利です。
Monitor の Terraform 管理の難しさ
一方で、Monitor を Terraform で管理するにはいくつかの難しさがあります。
Web UI の利便性
監視設定においては Web UI の利便性が大きなメリットになります。Monitor を作成する際には、クエリ結果のプレビューを見ながら閾値を調整する試行錯誤が必要です。評価結果の予測や閾値の調整は難しく、実運用上は Web UI 上で結果を確認しながら設定を詰めることがほとんどです。また、クエリの補完機能も Web UI でしか利用できません。
また、閾値を決める際には、Web UI であればクエリ結果を過去に遡ってその場で確認できます。このように、Web UI であるほうが便利な場面が多々あります。
すべてを Terraform 化する必要はない
Terraform 化はすべてがメリットばかりではありません。一時的な検証用の Monitor や、すぐに作って試したいケースでは、Web UI でサッと作るだけで十分な場合もあります。
そのため、私たちは Terraform 管理を必須とはせず、Web UI での作成も許容する運用をしています。試行錯誤は Web UI で行い、運用として確定したものを必要に応じて Terraform へ移行する、というアプローチを基本としています。すべてを Terraform 管理にすることが正解ではなく、Web UI でパッと作るだけで十分なケースもあります。それぞれのツールが得意なフェーズを見極めて共存させることが大切です。
Web UI から Terraform への移行
Web UI も Terraform も両方にメリットがありますが、今後の運用を考えると Terraform 管理したほうがメリットが多いと考えています。 そのため Web UI で作成した Monitor を Terraform 化することとなりますが、これはこれで骨が折れる作業で、後回しにされがちです。これを解決するために、次のようなアプローチを取っています。
Export to Terraform 機能の活用
Datadog の Web UI には Export to Terraform 機能があり、既存の Monitor から Terraform コードを生成できます。これを活用することで、手作業での変換を減らせます。
一方で不要なパラメーターが多く含まれたり、私たちのコードスタイルに合わなかったりするため、生成されたコードをそのまま使うことは難しいというのが実情です。あくまで変換のベースとして利用し、そこからリファクタリングを行っています。
生成 AI エージェントの活用
前述のとおり Export to Terraform 機能だけでは十分でないため、最近では生成 AI エージェント (Devin など) にこのリファクタリング作業を任せることもあります。
具体的には、Export to Terraform で生成されたコードと既存のコードベースを渡し、「Terraform 管理して」と指示しています。ウォンテッドリーでは Terraform の CI/CD に tfaction を利用しており、tfmigrate による terraform import をコード管理しつつ CI で適用する仕組みがあります。Devin にはこの import を試行させ、差分が出なくなるまで修正させることで、手作業なしに Terraform 化を完了させています。
Terraform 管理されている Monitor を判別できるようにする
Web UI での作成も許容する運用をしていると、どの Monitor が Terraform 管理されていて、どれを手動で変更してよいのかが UI 上から判別しにくくなります。
そこで、Terraform で管理する Monitor には以下のタグを付与しています。
terraform-managed:trueterraform-tfstate:<Terraform コードを管理するリポジトリ・ディレクトリ名>
このタグがあることで、設定を変更しようとしたエンジニアは UI 上で Terraform 管理されていることに気づけます。緊急時に UI から直接変更した場合でも、後で Terraform コードへの反映が必要であることがわかります。
実装としては、locals で共通タグを定義し、各 Monitor で tags を concat して使っています。なお、Datadog provider には AWS provider の default_tags のような機能がないため、このように手動で共通タグを付与する必要があります。
locals {
default_datadog_tags = [
"terraform-managed:true",
"terraform-tfstate:datadog"
]
}
resource "datadog_monitor" "example" {
name = "Example Monitor"
type = "query alert"
query = "..."
tags = concat(local.default_datadog_tags, ["service:example"])
}タグ付けを CI で検証する
タグの付け忘れを防ぐため、CI でタグの検証を行っています。前述の tfaction には Conftest による terraform plan 結果の検証機能があり、リポジトリに policy ディレクトリを用意するだけで自動的に実行されます。
以下は datadog_monitor リソースに対して必要なタグが付与されているかを検証するポリシーの例です。
package main
deny_missing_datadog_monitor_tags contains msg if {
resource := input.planned_values.root_module.resources[_]
resource.type == "datadog_monitor"
missing_msg := _get_missing_tags_message(resource)
missing_msg != ""
msg := missing_msg
}
_get_missing_tags_message(resource) = msg if {
not resource.values.tags
msg := sprintf("datadog_monitor.%s: missing required tags (terraform-managed, terraform-tfstate)", [resource.name])
}
_get_missing_tags_message(resource) = msg if {
resource.values.tags
existing_tag_keys := {split(tag, ":")[0] | tag := resource.values.tags[_]}
required_tags := {"terraform-managed", "terraform-tfstate"}
missing_tags := required_tags - existing_tag_keys
count(missing_tags) > 0
msg := sprintf("datadog_monitor.%s: missing required tags: %v", [resource.name, missing_tags])
}
_get_missing_tags_message(resource) = "" if {
resource.values.tags
existing_tag_keys := {split(tag, ":")[0] | tag := resource.values.tags[_]}
required_tags := {"terraform-managed", "terraform-tfstate"}
missing_tags := required_tags - existing_tag_keys
count(missing_tags) == 0
}これにより、Terraform で作成する Monitor には必ずタグが付与されるというルールを検証できるようにしています。
最後に
Datadog Monitor の管理において、Web UI と Terraform は補完し合う関係です。
- Web UI でサッと検証・作成し、必要に応じて後から Terraform 化する
- Terraform でコードレビューや一括変更のメリットを享受する
- タグを使って Terraform 管理されているかどうかを判別できるようにし、共存を可能にする
Terraform 管理は必須にせず部分的に管理するだけでも十分にメリットを享受できます。Monitor の Terraform 管理を検討している方は、まずは一部の Monitor から始めてみてはいかがでしょうか。皆さんの監視運用の一助となれば幸いです。