TerraformでPagerDutyを構築する

# TerraformでPagerDutyを構築する

この記事では、Terraformを使ってPagerDutyの以下6つの要素を一括で定義するサンプルコードを示します。

* オンコールユーザー登録 & 連絡手段設定
* エスカレーションポリシー
* オンコールスケジュール
* メンテナンスウィンドウ
* サービス本体
* Datadogインテグレーション

---

## 目次

2. [variables\_user.tf の解説](#variables_usertf-の解説)
3. [variables\_service.tf の解説](#variables_servicetf-の解説)
4. [main\_user.tf の解説](#main_usertf-の解説)
5. [main\_service.tf の解説](#main_servicetf-の解説)

   1. [1) エスカレーションポリシー](#1-エスカレーションポリシー)
   2. [2) オンコールスケジュール](#2-オンコールスケジュール)
   3. [3) メンテナンスウィンドウ](#3-メンテナンスウィンドウ)
   4. [4) サービス本体](#4-サービス本体)
   5. [5) Datadogインテグレーション](#5-Datadogインテグレーション)


## variables\_user.tf の解説

オンコール対象ユーザーを外部から指定できるように変数を定義します。

```hcl
// variables_user.tf

variable "oncall_users" {
  description = "オンコールユーザーのリスト"
  type = list(object({
    name  = string  # 名前
    email = string  # メールアドレス
  }))
}
```

* `oncall_users`：名前とメールアドレスを持つユーザーリストを想定

---

## variables\_service.tf の解説

サービス全般やメンテナンスウィンドウ、Datadog連携の設定を定義します。

```hcl
// 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上でユーザーと連絡手段を作成します。

```hcl
// 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"
}
```

1. **pagerduty\_user**

   * `for_each` で渡されたリスト分だけユーザーを作成
   * `role = "user"` で一般ユーザー権限を付与
2. **pagerduty\_user\_contact\_method**

   * 各ユーザーにメール連絡手段を登録

---

## main\_service.tf の解説

`variables_service.tf` の変数を活用し、エスカレーションからDatadog連携までを一気に定義します。

### 1) エスカレーションポリシー

```hcl
// 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) オンコールスケジュール

```hcl
// 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) メンテナンスウィンドウ

```hcl
// 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) サービス本体

```hcl
// 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インテグレーション

```hcl
// 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](giranm/pagerduty-terraform-quickstart)

リポジトリには、今回ご紹介した「オンコールユーザー登録」「エスカレーションポリシー」「スケジュール」「メンテナンスウィンドウ」「サービス定義」「Datadog連携」が一通り動作するサンプルコードがまとまっています。