【Google Cloud】Terraformで稼働時間チェック（Uptime Checks）による外形監視を設定

## 概要

Cloud Monitoring の「稼働時間チェック」に関して、以下の内容を記載します。

- 外形監視としての設定
- 無料枠について
- Terraform で構築する場合の例

## 稼働時間チェック（Uptime Check）とは

稼働時間チェックとは、リソースが使用可能で、想定どおりに動作しているかどうかを判断するために設定する監視のためのリソースです。

https://cloud.google.com/monitoring/uptime-checks/introduction?hl=ja

チェックのための通信プロトコルとしては、TCP、HTTP、HTTPSに対応しており、追加でICMPのチェックも設定することができます。

正常か異常かの判定は、HTTPレスポンスコードやコンテンツマッチ（特定の文字列を含むかどうか）で設定します。

https://cloud.google.com/monitoring/uptime-checks/response-validation?hl=ja


インターネットに一般公開されたリソースと、IAMやVPC内で制限されたリソースで設定方法が異なります。
本記事では、インターネットに公開されたリソースを対象とした稼働時間チェックについて記載します。

https://cloud.google.com/monitoring/uptime-checks?hl=ja



### 外形監視としての設定

監視対象として、一般公開されたURLを指定することで外形監視として設定できます。

監視対象へのリクエスト元については、グローバルを選択するか、以下のロケーションから最低3つ以上を選択します。
グローバルを選択した場合は、全てのロケーションから稼働時間チェックのリクエストが送信されます。

- アジア太平洋
- ヨーロッパ
- 南アメリカ
- 米国（アイオワ）
- 米国（オレゴン）
- 米国（バージニア）

リクエスト元のIPアドレスについては、管理コンソールなどからリストを取得することができます。
そのため、監視対象のアプリケーションで監視用のエンドポイントを作成し、IPアドレスベースでアクセスを制限したい場合などにも対応することができます。

IPアドレスのリストは、管理コンソールからリストをダウンロードすることができます。

![uptime-check-ip-list-dl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510411/2fddce95-eaea-bf38-f927-3afc88254476.png)

IPアドレスのリストは、APIからも取得可能です。詳細は以下を参照ください。

https://cloud.google.com/monitoring/uptime-checks/using-uptime-checks?hl=ja#monitoring_uptime_check_list_ips-console

### 無料枠について

正確な情報については、公式ドキュメントをご参照ください。

https://cloud.google.com/stackdriver/pricing?hl=ja#pricing_examples_uptime

:::note warn
以下は、2023.6.29 時点での情報ですので、ご注意ください。
:::

料金体系として、「Google Cloud プロジェクトあたり 100 万の実行」が無料枠として割り当てられており、
超過した分は 1,000 回の実行あたり $0.30 の課金となります。

そのため、チェックの実行頻度を1分、リージョン数を3(最小)とした場合、
```
3リージョン x 60分 x 24時間 x 31日 = 133,920回 / 月 
1,000,000 ÷ 133,920 ≒ 7.46
```
となります。

そのため、監視対象としてはプロジェクト毎に **7つ** までは無料枠に収まる計算になります。

### Terraform で構築する場合の例

Terraformの Google Cloud Platform Provider を利用した例を記載します。
プロバイダについては以下を参照ください。

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

:::note warn
筆者の環境では、構築するためにGoogle Providerのバージョンが4.17.0だと正常に構築できず、4.47.0 に上げる必要がありました。
エラーが出た際は、プロバイダーのバージョンを確認してみてください。
（特に理由がなければ、構築時の最新バージョンに上げるのが無難かと思います）
:::

利用するリソースに対応するTerraformのリファレンスは以下から確認できます。

- [稼働時間チェック - google_monitoring_uptime_check_config](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/monitoring_uptime_check_config)
- [アラートポリシー - google_monitoring_alert_policy](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/monitoring_alert_policy)

コードの例では、要点をコメントで記載しています。

```uptime_check_sample.tf
resource "google_monitoring_uptime_check_config" "https_check" {
  display_name = "外形監視のテスト"
  timeout      = "10s"
  period       = "60s"  # チェックの頻度。費用に関わるので設定に注意

  # selected_regions を記載しないとGLOBAL（全リージョン）からののチェックとなる。
  selected_regions = [
    "ASIA_PACIFIC",
    "EUROPE",
    "USA_VIRGINIA",
  ]

  # 監視対象が HTTP(S) の場合は設定
  http_check {
    path         = "/"
    port         = "443"
    use_ssl      = true
    validate_ssl = true
    accepted_response_status_codes {
      status_value = 200 # status_class = "STATUS_CLASS_2XX" のように記載も可能です。
    }
  }

  monitored_resource {
    type = "uptime_url"
    labels = {
      project_id = "my-project-name"
      host       = "example.com"  # 監視対象のホスト名またはIPアドレスを記載します
    }
  }

  # レンスポンスデータの検証のための設定です。
  content_matchers {
    content = "OK"
    matcher = "CONTAINS_STRING"  # MATCHES_REGEX で正規表現での記載も可能です。
  }

  checker_type = "STATIC_IP_CHECKERS"
}
```

```alert_policy.tf
resource "google_monitoring_alert_policy" "https_check_alert" {
  display_name = "外形監視のアラート"
  combiner     = "OR"
  conditions {
    display_name = "外形監視のアラート"

    condition_threshold {
      # filter に 稼働時間チェックの指標を指定して、関連づけています。
      filter          = "resource.type = \"uptime_url\" AND metric.type = \"monitoring.googleapis.com/uptime_check/check_passed\" AND metric.labels.check_id = \"${google_monitoring_uptime_check_config.https_check.uptime_check_id}\""
      duration        = "0s"
      threshold_value = 1  # 失敗が1回より多くなったときにアラートを通知
      comparison      = "COMPARISON_GT"
      aggregations {
        alignment_period     = "1200s"
        cross_series_reducer = "REDUCE_COUNT_FALSE"
        per_series_aligner   = "ALIGN_NEXT_OLDER"
      }
      trigger {
        count   = 1
        percent = 0
      }
    }
  }

  # 通知先の定義は、別途定義が必要です。
  # 認証まわりをTerraformで管理したくないため、通知チャンネルは管理コンソールから手動で追加し、data source で利用することを想定した例となっています。
  notification_channels = [
    data.google_monitoring_notification_channel.slack.id,
  ]

  # 通知内容について、対応しているMarkdownの書式や利用できる変数については以下に記載があります。
  # https://cloud.google.com/monitoring/alerts/doc-variables?hl=ja
  # Slackでメンションをつける際にはいくつか特殊な書き方をする必要があります。
  # channel のメンション: <!channel>
  # ユーザのメンション: <@taro>
  # ユーザグループのメンション: <!subteam^XXX}> 
  # XXXはユーザグループIDです。IDは、Slack APIかブラウザでユーザグループの画面を開いた際のURLから取得できます。グループ名そのままで指定はできないので注意してください
  documentation {
    content   = <<-EOT
    <!channel> 外形監視のアラートテストです。
    EOT
    mime_type = "text/markdown"
  }

  user_labels = { "severity" : "info" }
  enabled     = true

  depends_on = [
    google_monitoring_uptime_check_config.https_check
  ]

  # 稼働時間チェックの作り直しが必要な変更をした際に、アラートポリシーも作り直す
  lifecycle {
    replace_triggered_by = [
      google_monitoring_uptime_check_config.https_check.id
    ]
  }
}
```


google_monitoring_alert_policy.https_check_alert で設定している lifecycle ブロックの　`eplace_triggered_by` については以下を参考ください。

https://qiita.com/bosq/items/9671150eaab052d5baea

## まとめ

稼働時間チェックによる外形監視の設定について記載しました。
URLに対して決まったレスポンスがあるかどうかなどの単純な監視設定であれば、Slack通知するところまで簡単に設定でき、有用なツールになりそうだと思って今回記事を執筆しました。

以上、この記事が誰かの役に立てれば幸いです。

## 関連情報

稼働時間チェックの調査をする際に、以下の記事が大変わかりやすく参考になりました。

https://engineers.ntt.com/entry/2023/03/30/095415