はじめての監視実装をGitLab Runnerでやってみて学んだこと

こんにちは! 技術本部の技術戦略ディビジョンで主にEOL対応巻き取りなどをしているインフラエンジニアの片岡です。

この記事では、以下の内容を書いています。

  • 監視実装をやったことが無かった人が0から監視に取り組んで学んだこと
    • 本当に重要な問題にアラートを発報するという原則
    • ワークメトリクスからリソースメトリクスへ掘り下げる考え方
  • セルフホストのGitLab Runnerにおいての監視で工夫した点

特にシステムの監視をどのように取り掛かれば良いか分からない方の参考になれば嬉しいです。

背景

そもそも、GitLab Runnerの監視に取り掛かった背景から説明します。

流れとしては以下の通りです。

  1. 社内で運用しているGitLab Runnerのリアーキテクチャを実施
  2. リアーキテクチャ対応後、AWS Configコストが急上昇した(通常時の5倍近く)
  3. コスト管理をする別部署から指摘を受けて気づいた
  4. 原因は、RunnerのEC2インスタンスが起動終了を繰り返すことによるもの
    • Auto ScalingでEC2インスタンスを起動しています
  5. インスタンスの起動終了が繰り返されるのはバグが原因だった
  6. issue: gitlab-runner #37673
  7. 以前のDatadogを使った監視では不十分で、監視の経験もなかったので、勉強目的も兼ねて再度0ベースで監視実装の機会をいただけた
  8. 別部署からの指摘ではなく自分たちで気づけるようにするべきだと判断した

社内のセルフホストのGitLab Runnerについての補足

今回のブログの内容をイメージしやすくするために、AWS上でのセルフホストGitLab Runnerについての構成を簡単に書きます。

  • Runner Manager: Runner Instanceを生成するEC2インスタンス
    • ondemand-001, 002(ondemandのRunner Instanceを生成)
    • spot-001, 002(spotのRunner Instanceを生成)
  • Runner ManagerはEC2のAuto Scaling Groupを使ってRunner Instanceを生成
    • ASGの操作はFleeting pluginを使用する
  • Runner Instance: ジョブを実行するEC2インスタンス
    • 各Runner Managerから複数台生成される
    • Runner Instance上では、Dockerでジョブを実行

監視実装の流れ

まず、Datadogの資料をインプットしました。

他にはオライリーの「入門 監視」なども読みましたが、これらのインプットを踏まえ、監視設計では以下の考え方を特に重視しました。

  • ワークメトリクスとリソースメトリクスを分ける
    • ワークメトリクス: システムのトップレベルのヘルスを示すメトリクス
      • 例) ジョブ成功数、エラー数、パフォーマンスなど
    • リソースメトリクス: 下位のシステムや、低レベルのリソースについてのメトリクス
      • 例) CPU、メモリ、ディスクなど
  • ワークメトリクスでシステムを診断し、リソースメトリクスで問題の原因を突き止める
  • 本当に重要な問題に対してアラートを実施する
    • アラートする: システム起因でジョブが失敗し続けている
    • アラートしない: EC2インスタンスのCPU利用率が90%を超えている

オライリーの本ではワークメトリクスという表現はしておりませんが、以下の引用文のように似たような主張をしております。

CPUやメモリ使用率のような低レベルなメトリクスではなく、「動いているか」を基準にアラートを送ることが有益である

これを受けて、実装では以下のアプローチを取りました。

  1. ユーザーニーズを想定する
  2. ユーザーニーズが満たされているか確認(監視)する方法を調査・検証
  3. 実際にアラート(Slackチャンネルに通知)する項目(ワークメトリクス)の選定
  4. 実際に収集し、閾値を設けてアラートを設定

各フェーズについて説明します。

1. ユーザーニーズを想定する

本来このフェーズでは、ビジネスKPIやSLA(サービス水準合意)、SLI(サービス水準指標)を見て整理すべきです。

今回はCI/CD実行時に最低限求められるであろうニーズの仮説を自分たちで立てる形にしました。

自分たちの部署が一番のユーザーであり、普遍的なニーズが想像できると判断したためです。

以下のように定性的な表現でいくつか候補を列挙しました。

  • CI/CDジョブが正常に成功する
  • CI/CDジョブの実行時間が許容範囲内
  • 24時間いつでもジョブが実行できる
  • ジョブのログが正しく取得できる
  • ジョブの成果物やキャッシュを正しく保存・取得できる

またユーザーは気にしないものの、管理者は気にする観点として、AWSリソースコストも候補に入れました。

これは単純にコストが急上昇していないかという観点です。

2. ユーザーニーズを特定の指標として計測する方法を調査・検証

以前から使っていたDatadogを引き続き使うことにしたので、Datadogに収集できる前提で上記のユーザーニーズを定量的に測るメトリクスを調査・検証しました。

例えば、以下はGitLab Runnerが公開しているPrometheusメトリクス(Datadog側の参照名)の例です。

ジョブの失敗数カウント: gitlab_runner.gitlab_runner_failed_jobs_total
CI/CDジョブの実行時間: gitlab_runner.gitlab_runner_job_duration_seconds

Runner ManagerにはDatadog Agentをインストールし、Runner InstanceにはCloudWatch Agentをインストールして収集する形にしました。

AWS Configについては、aws.config.* メトリクスをDatadog Integrationで取得できることも確認できました。

3. 実際にアラート(Slackチャンネルに通知)する項目(ワークメトリクス)の選定

実際にアラートに設定したのは以下の項目です。

  • システム起因のジョブ失敗率
    • 選定理由: CI/CDジョブが正常に成功することを監視するため
  • ジョブ成功率
    • 選定理由: システム起因のジョブ失敗率では漏れてしまう部分を補うため
      • 詳細は工夫した点で後述します
  • ジョブ実行時間
    • 選定理由: ランナーのジョブ実行のパフォーマンスを時間ベースで検知するため
      • ジョブの平均実行時間が長くなるのはジョブの内容次第ですが、極端に長い場合は異常である可能性が高いため、検知対象としました
  • Runner Managerの死活監視
    • 選定理由: 24時間いつでもジョブが実行できる点を監視するため
  • ジョブの成果物やキャッシュを正しく保存・取得できる
    • 選定理由: ジョブのキャッシュの保存・取得のみができない場合、他のアラートでは検知できないため
    • こちらはメトリクス自体はなかったのですが、定期ジョブでキャッシュの保存・取得を実行することで実現しました
  • AWS Config利用量
    • 選定理由: GitLab Runnerを構成するAWSリソースの中で大きく膨れうるものがAWS Configのみだったため
    • また、今回のきっかけでもあったので特に確認すべきだと判断しました

また、問題が発生した際に原因を追求しやすくするため、リソースメトリクスも収集することにしました。

いくつか例を挙げると以下のとおりです。

  • Runner ManagerのCPU使用率
  • Runner Managerのディスク使用率
  • Runner ManagerのネットワークI/O
  • Runner Instanceのディスク使用率
    • Dockerで動かすため、imageのキャッシュが溜まり続けてしまうケースを懸念して数値として見られる状態にはしました
    • Runner Instanceはジョブが一定回数実行されるとInstanceの削除と再作成が行われるので、アラート設定までは実施しませんでした

4. 実際に収集し、閾値を設けてアラートを設定

本番系で実際に収集したデータをもとに、3.で選定した項目ごとに閾値を設定しました。

なお、Datadogには異常検知(Anomaly Detection Monitor)のような閾値Monitor以外の検知方式もあります。

しかし、これらは上位プラン限定で追加コストが発生するため、今回は閾値Monitorによるアラート設定に統一しました。

各項目の閾値は以下のとおりです。

  • システム起因のジョブ失敗率 / ジョブ成功率
    • 閾値の決め方が難しい部分がありました
    • 詳細は「工夫した点」に書きます
  • ジョブ実行時間
    • ジョブの上限が3時間のため、直近1時間で実行されたジョブ全体の中央値が2時間55分以上となった場合をアラート条件としました
  • Runner Managerの死活監視
    • 4台中1台のみ稼働中となった場合にアラートを発報する
  • ジョブの成果物やキャッシュの保存・取得
    • 定期実行ジョブの結果が失敗した場合にアラートを発報する
  • AWS Config利用量
    • 平常時の変動が小さいので、直近1か月の最大値の1.5倍ほどを閾値とする

工夫した点

ジョブ成功率のアラートについて

GitLab Runnerで収集できるジョブ失敗数メトリクスは、script_failurerunner_system_failure のように失敗理由別でカウントを絞れます。

当初は、ユーザースクリプト由来の script_failure を除外し、システム起因の失敗のみを対象にアラートすればよいと考えていました。

しかし、セルフホストで運用しているため、ネットワーク関連やオンプレのDNSサーバーとの通信設定なども自分たちで管理しています。

この場合、例えばネットワーク設定に問題があり、ジョブ上で接続失敗が起こったとしても script_failure としてカウントされてしまうケースがあります。

そのため、runner_system_failure を含めてカウントすべきだと判断し、全体の失敗率を1から引いた成功率もアラート設定して異常に気づけるようにしました。

閾値設定

成功率のアラートについても設定が難しい部分がありました。

評価ウィンドウ(直近x時間)内にジョブが全く実行されない時間帯があります。

この時間帯では、少数のジョブが連続して失敗すると成功率が急低下してアラートが発報され、その後すぐに回復するという挙動になりました。

これについては、以下のような葛藤がありました。

  • 単にウィンドウを伸ばす → 急変動を小さくできるが、問題が発生した際の反応速度が遅くなる点を懸念
  • 低い閾値(5%など)に設定する → 普段は10%程度で推移しているが、実は一部のRunner Managerで実行されるジョブが失敗し続けているような場合に、問題があるのに反応できていない状態を懸念

そのため、以下のように2つのアラートに分割しました。

  • ジョブ成功率の急低下に反応できるアラート
    • 直近3時間のジョブ成功率が10%を下回る
  • 慢性的なジョブ成功率低下に反応できるアラート
    • 1日の全ジョブ成功率が80%を下回る

定期実行ジョブも多くあり、それらは基本的に成功するため、1日平均のジョブ成功率は90%近くで推移していました。

この前提があったため、上記のような設定にしました。

AWS Config料金の異常検出について

監視整備のきっかけとなったのは、AWS Configコストの急上昇でした。

この異常検出は、AWS Cost Anomaly DetectionなどのAWS標準のコスト異常検出機能でも実装できます。

しかし、下記の理由から、AWS Configの利用量メトリクス(ConfigurationItemsRecorded)を直接監視し、直近1か月の最大使用量の1.5倍ほどを閾値としてアラート設定する方式にしました。

  • AWS Cost Anomaly Detectionは検知までに最大24時間の遅延がある
    • AWS Cost Anomaly DetectionはCost Explorerのデータに依存しており、Cost Explorerのデータ反映には最大24時間かかるため
    • 一方、AWS Config利用量はCloudWatchメトリクス(ConfigurationItemsRecorded)として比較的早く反映されるため、より早期に検知できる
  • AWS Config以外のリソースは設計的にコスト異常増加には繋がらない
    • 例えばAuto ScalingのEC2インスタンスは最大台数が制限されているため、異常増加する懸念がない

稼働中Runner Manager数を監視することについて

この監視をするに至った経緯としては下記のようなケースを懸念したためです。

  1. ジョブの成功率、失敗率などのCI/CD実行状況のみに対して異常検知する
  2. 一部Runner Managerインスタンスが意図せず停止してしまう
  3. 残りの生きているRunnerのみでジョブが回り続ける
  4. CI/CD実行状況としては異常として検知されない
  5. すべてのRunnerが意図せず停止してしまってから異常事態に気がつく

Runnerが全台消失する事態を防ぐため、稼働中のRunner Manager数の監視も実装しました。

良かったところ

  • Claude Codeで、メトリクスの収集設定やDatadog MonitorのIaC化を効率よく進められました
    • TerraformによりIaC化をしていたので、改善がしやすかったです
    • 特にDatadogではpup(Datadog CLI)があるため、CLI経由でのDatadogの調査・検証を迅速に行えました
  • 監視についてのドキュメント(上に挙げたDatadogの資料など)を読んで実際に自分で実装することで、学びが深まった感触がありました

今後について

  • 様々なシステムでアラートすべき事項は変わってくると考えられるため、今後さらに学んでいきたいです
  • リソースメトリクスを深く調べることで、パフォーマンスの最適化を進めていきたいです
  • 問題発生時にAIが一次調査を自動実行する仕組みも整備していきたいと考えています