TerraformでPagerDutyを構築する
この記事では、Terraformを使ってPagerDutyの以下6つの要素を一括で定義するサンプルコードを示します。
- オンコールユーザー登録 & 連絡手段設定
- エスカレーションポリシー
- オンコールスケジュール
- メンテナンスウィンドウ
- サービス本体
- Datadogインテグレーション
目次
variables_user.tf の解説
オンコール対象ユーザーを外部から指定できるように変数を定義します。
// variables_user.tf
variable "oncall_users" {
description = "オンコールユーザーのリスト"
type = list(object({
name = string # 名前
email = string # メールアドレス
}))
}
-
oncall_users
:名前とメールアドレスを持つユーザーリストを想定
variables_service.tf の解説
サービス全般やメンテナンスウィンドウ、Datadog連携の設定を定義します。
// variables_service.tf
variable "service_name" {
description = "PagerDuty サービス名"
type = string
}
variable "service_description" {
description = "PagerDuty サービス説明"
type = string
}
variable "integration" {
description = "有効化するインテグレーション"
type = object({ datadog = bool })
default = { datadog = true }
}
variable "vendors" {
description = "ベンダー情報"
type = object({
datadog = object({
id = string # Datadog ベンダーID
name = string # Datadog ベンダー名
})
})
}
variable "urgency" {
description = "インシデントの緊急度(high または low)"
type = string
default = "high"
}
variable "maintenance_windows" {
description = "メンテナンスウィンドウの設定リスト"
type = list(object({
start_time = string # ISO8601 形式
end_time = string # ISO8601 形式
description = string # 説明
}))
}
- サービス名・説明、緊急度、メンテナンスウィンドウ、Datadog連携設定を外部化
main_user.tf の解説
variables_user.tf
で受け取ったユーザー情報をもとに、PagerDuty上でユーザーと連絡手段を作成します。
// main_user.tf
resource "pagerduty_user" "main" {
for_each = { for u in var.oncall_users : u.email => u }
name = each.value.name
email = each.value.email
role = "user"
}
resource "pagerduty_user_contact_method" "main" {
for_each = pagerduty_user.main
user_id = each.value.id
type = "email_contact_method"
address = each.value.email
label = "Work"
}
-
pagerduty_user
-
for_each
で渡されたリスト分だけユーザーを作成 -
role = "user"
で一般ユーザー権限を付与
-
-
pagerduty_user_contact_method
- 各ユーザーにメール連絡手段を登録
main_service.tf の解説
variables_service.tf
の変数を活用し、エスカレーションからDatadog連携までを一気に定義します。
1) エスカレーションポリシー
// main_service.tf
resource "pagerduty_escalation_policy" "main" {
name = "${var.service_name} Escalation Policy"
num_loops = 1
rule {
escalation_delay_in_minutes = 30
target {
type = "schedule"
id = pagerduty_schedule.main.id
}
}
}
-
num_loops
:エスカレーション回数(ここでは1回) -
rule
:30分後にオンコールスケジュールへエスカレーション
2) オンコールスケジュール
// main_service.tf
resource "pagerduty_schedule" "main" {
name = "${var.service_name} Primary Schedule"
description = "Primary on-call rotation"
time_zone = "Asia/Tokyo"
# 平日日中レイヤー
layer {
name = "Workday Rotation"
start = "2020-06-21T00:00:00+00:00"
rotation_virtual_start = "2020-06-21T07:00:00+00:00"
rotation_turn_length_seconds = 86400
users = [for u in values(pagerduty_user.main) : u.id]
restriction {
type = "weekly_restriction"
start_day_of_week = 1 # 月曜日
start_time_of_day = "09:00:00" # 09:00 〜
duration_seconds = 28800 # 8時間
}
# 他の平日制限も同様に追加
}
# 夜間レイヤー
layer {
name = "Nightshift Rotation"
start = "2020-06-21T00:00:00+00:00"
rotation_virtual_start = "2020-06-21T07:00:00+00:00"
rotation_turn_length_seconds = 86400
users = [for u in values(pagerduty_user.main) : u.id]
restriction {
type = "weekly_restriction"
start_day_of_week = 1 # 月曜日
start_time_of_day = "17:00:00" # 17:00 〜
duration_seconds = 57600 # 翌09:00 まで
}
# 他の曜日も同様に追加
}
}
- layer:複数レイヤーで日中/夜間など細かくローテーション可
- restriction:週◯曜◯時〜の時間制限を設定
3) メンテナンスウィンドウ
// main_service.tf
resource "pagerduty_maintenance_window" "main" {
for_each = { for idx, mw in var.maintenance_windows : idx => mw }
start_time = each.value.start_time
end_time = each.value.end_time
description = each.value.description
services = [pagerduty_service.main.id]
}
-
start_time
/end_time
は ISO8601 フォーマット
4) サービス本体
// main_service.tf
resource "pagerduty_service" "main" {
name = var.service_name
description = var.service_description
escalation_policy = pagerduty_escalation_policy.main.id
alert_creation = "create_alerts_and_incidents"
acknowledgement_timeout = 7200
incident_urgency_rule {
type = "constant"
urgency = var.urgency
}
}
- acknowledgement_timeout:対応者のアクノレッジ猶予(秒)
5) Datadogインテグレーション
// main_service.tf
resource "pagerduty_service_integration" "main_datadog" {
count = var.integration.datadog ? 1 : 0
name = var.vendors.datadog.name
vendor = var.vendors.datadog.id
service = pagerduty_service.main.id
}
resource "datadog_integration_pagerduty_service_object" "main" {
count = var.integration.datadog ? 1 : 0
service_name = var.service_name
service_key = pagerduty_service_integration.main_datadog[0].integration_key
}
- count = var.integration.datadog ? 1 : 0 で有効化制御
サンプルコードの参照
実際のTerraform構成例として、以下のリポジトリを参考にするとさらに理解が深まります。
GitHub
リポジトリには、今回ご紹介した「オンコールユーザー登録」「エスカレーションポリシー」「スケジュール」「メンテナンスウィンドウ」「サービス定義」「Datadog連携」が一通り動作するサンプルコードがまとまっています。