🐶

Cloud RunのSLOをTerraformを用いてDatadog上に作成する

2023/12/07に公開

この記事は 検索エンジンプロダクトを一緒に開発してた同窓会 Advent Calendar 2023 の6日目の記事です。
昨日は mado さんの GitHubのメンバーとチームをTerraformで管理する でした。

はじめに

信頼性 の高いプロダクト開発運用のために、 SLO を用いて開発と運用のバランスを合理的に判断するのは良いプラクティスです。
ここでは Cloud Run のavailabilityとlatencyのSLOを作成してみます。
Google Cloud上でも Cloud Monitoring でSLOは作成できますが、Datadogの通知は多機能で扱いやすいためDatadogにTerraformを用いて実装してみます。

availability

SLOにはリクエスト数に応じた メトリクスベースSLO と時間帯に応じた モニターベースSLO があります。
メトリクスベースの方が定義や設定がシンプルなのでこちらを使います。

SLO

datadog_service_level_objective リソースを使います。
使用するメトリクスはGoogle Cloudインテグレーションの標準メトリクスである gcp.loadbalancing.https.request_count が使えそうです。

ここでは以下の条件でSLOを作成してみます。

  • 正常に処理(ステータスが5xx以外)のリクエスト割合が過去30日で99.9%以上。
resource "datadog_service_level_objective" "availability" {
  name = "availability"
  type = "metric"

  query {
    denominator = <<-TOTAL
      sum:gcp.loadbalancing.https.request_count{(response_code_class:200 OR response_code_class:300 OR reponse_code_class:400 OR response_code_class:500 )}.as_count()
    TOTAL
    numerator   = <<-GOOD
      sum:gcp.loadbalancing.https.request_count{(response_code_class:200 OR response_code_class:300 OR reponse_code_class:400 )}.as_count()
    GOOD
  }

  thresholds {
    timeframe = "30d"
    target    = 99.9
  }
}

特定の日時の除外

リリース時のダウンタイムやアクセスの少ない時間帯などをSLOの対象から除きたいこともあります。
datadog_slo_correction を用いることで実現できます。

ここでは以下の条件を設定します。

  • 毎日22:00~08:00はSLOから除外する。
resource "datadog_slo_correction" "availability_midnight" {
  category = "Outside Business Hours"
  start    = 1672578000 # 2023/01/01 22:00, 時刻だけ重要で日付は十分に過去であればいつでも良い
  rrule    = "FREQ=DAILY;INTERVAL=1"
  duration = 36000 # 10 hours
  slo_id   = datadog_service_level_objective.availability.id
  timezone = "Asia/Tokyo"
}

エラーバジェット

SLOを運用するには エラーバジェット のモニタリングが有効です。
datadog_monitor リソースのtypeに slo alert を設定することで残エラーバジェットに応じたアラート設定を実現できます。

ここではエラーバジェットが尽きた時に通知してくれるアラートを設定します。

resource "datadog_monitor" "availability_error_budget" {
  name    = "Error Budget Alert on availability SLO"
  type    = "slo alert"
  message = "@sample-mention"

  query = <<-QUERY
    error_budget("${datadog_service_level_objective.availability.id}").over("30d") > 100
  QUERY

  monitor_thresholds {
    critical = 100
  }
}

バーンレート

エラーバジェットだけだと急なバジェットの消費に気が付き辛いので、 バーンレートアラート を設定するのも有効です。
エラーバジェットと同じく datadog_monitor リソースのtypeに slo alert を設定することで実現できます。

バーンレート設定の微調整は難しいですが、 Datadogのドキュメント に推奨の期間や値が載っているので参考にします。

resource "datadog_monitor" "availability_burn_rate" {
  name    = "Burn Rate Alert on availability SLO"
  type    = "slo alert"
  message = "@sample-mention"

  query = <<-QUERY
    burn_rate("${datadog_service_level_objective.availability.id}").over("30d").long_window("6h").short_window("30m") > 6
  QUERY
  monitor_thresholds {
    critical = 6
  }
}

latency

複数の CUJ に対応するために特定のエンドポイントごとに柔軟にlatencyのSLOを設定しようと思います。
しかし、DatadogのGoogle Cloudインテグレーションでの標準メトリクスではエンドポイントごとのlatencyが取得できません。
よって、ここではCloud RunのログをベースにSLOを作成してみます。

DatadogではメトリクスベースのSLOにログを用いることはできないため、ログを基にしたmonitorから モニターベースSLO を作成してみます。
また、以下のようにログモニターはSLOに対応していないため、ログからカスタムメトリクスを作成し、カスタムメトリクスのmonitor経由でSLOを作成してみます(ややこしい)

Datadog のモニターベースの SLO は、以下のモニタータイプをサポートしています。

  • メトリクスモニターの種類 (メトリクス、インテグレーション、APM メトリクス、異常検知、予測値、外れ値)
  • Synthetic
  • サービスチェック (オープンベータ)

ここでは以下の条件でSLOを作成してみます。

  • レスポンスタイムのp90が500msec以下である時間帯の割合が過去30日で98%以上

カスタムログメトリクス

datadog_logs_metric リソースを用いてログベースのカスタムメトリクスが作れます。
ログの logs/run.googleapis.com%2Frequests フィールドの duration を集計します。
name は任意のメトリクス名です。

ちなみにDatadogのカスタムメトリクスは付与されたタグの掛け算で課金されるため、 思わぬ高額請求に注意 しておくと良いと思います。

resource "datadog_logs_metric" "latency" {
  name = "log.metric.api.backend.request.duration"
  compute {
    aggregation_type    = "distribution"
    path                = "@duration"
    include_percentiles = true
  }
  filter {
    query = "@data.logName:\"projects/sample-project/logs/run.googleapis.com%2Frequests\" status:ok"
  }
}

モニター

作成したログベースのカスタムメトリクスを基にモニターを作成します。

resource "datadog_monitor" "latency_slo_base" {
  name    = "latency SLO base"
  type    = "query alert"
  message = <<-MESSAGE
    This monitor is used only as a base for SLO.
    Not used for alerts.
  MESSAGE

  query = <<-QUERY
    percentile(last_1m):p90:log.metric.api.backend.request.duration{*} / 1000000 > 500
  QUERY

  monitor_thresholds {
    critical = 500
  }
}

SLO

作成したモニターを基にtypeを monitor に設定してSLOを作成します。

resource "datadog_service_level_objective" "latency" {
  name        = "latency"
  type        = "monitor"
  monitor_ids = [datadog_monitor.latency_slo_base.id]

  thresholds {
    timeframe = "30d"
    target    = 0.98
  }
}

除外日時やエラーバジェットやバーンレートに関してはavailabilityと同じ設定で可能なため割愛します。

最後に

Cloud RunのSLOををTerraformを用いてDatadog上に作成できました。
除外日時の設定やエラーバジェット・バーンレートを用いたアラート設定も簡単にできます。
ただ、availabilityに関してはシンプルに設定できましたが、latencyに関してはリソース数が増えてちょっと複雑になってしまったので改善の余地はありそうです。
Google Cloud側でもlatencyのSLO作成は可能なので、よりより実装を目指して今後も改善を重ねていこうと思います。

Discussion