Datadogの監視基準
Datadog Agentが収集するシグナル、初期monitorのしきい値、DB点検query、定義を適用して検証する方法
このドキュメントは、サーバーデプロイで確認する最小の監視基準です。Kubernetes(Helm)インストールでプラットフォームが出すメトリクスは、プラットフォームのメトリクス(Kubernetes)にあります。アプリにDatadog SDKは入れません。セッションのトレースは、設定したときだけ標準のOTLPで出力します(デフォルトはオフで、特定のコレクターは不要です)。キーはAPIサーバー運用ドキュメントにあります。ここで説明するDatadog Agentはトレースではなく、ログ・/readyz・DB・ホストを見ます。Datadog Agentが、DockerのJSON stdoutログ、/readyz、読み取り専用のPostgreSQL query、ホストのメトリクスを収集します。定義はinfra/datadog/definitionsだけでバージョン管理し、このリポジトリのツールやCIはDatadog APIを呼び出しません。
すべてのしきい値は、サーバーデプロイ後の最初の7日間で調整する初期値です。threshold_stage:first-week-tuning tagが付いたmonitorを、最初の週のデータなしに長期の基準とみなしません。すでに埋めた空白はなし、その範囲外のためサーバーデプロイ後に優先度を決め直す項目はデプロイ後に判断と表記します。
起動とシークレットの管理
Agentは、選択式のinfra/compose.datadog.ymlでだけ作られます。このファイルを指定しない既定のstackには、Agent、mount、label、必須の環境変数が1つも追加されません。Agentのimageはgcr.io/datadoghq/agent:7.83.3に固定します。
DD_API_KEYとDatadog用のPostgreSQL passwordは、リポジトリやshell historyに入れません。サーバーで運用者が/etc/werft/datadog.envを作り、mode 600を確認します。別の絶対パスを使う必要があるときだけDATADOG_ENV_FILEで変えます。値は例のプレースホルダーなので、実際の値をドキュメント・チケット・ログにコピーしません。
DD_API_KEY=<operator-supplied>
DD_SITE=datadoghq.com
DD_ENV=alpha
DD_VERSION=<release-sha>
DD_POSTGRES_PASSWORD=<read-only-role-password>sudo chown root:root /etc/werft/datadog.env
sudo chmod 600 /etc/werft/datadog.env
stat -c '%a %U:%G' /etc/werft/datadog.envAgent serviceは、この絶対パスをenv_fileとしてだけ読みます。compose YAMLにはDD_API_KEYの名前も値のinterpolationもないので、ambientのDD_API_KEYで迂回できません。DD_ENVとDD_VERSIONは、同じファイルをcomposeの--env-fileとして読み、product containerのunified tagsに使います。
PostgreSQL roleは、queue_messages、sessions、turns、attempts、provider_usageにSELECTだけを許可し、既定のtransactionをread-onlyに固定します。次のコマンドは、サーバーの運用者がadmin connectionで1回実行します。
CREATE ROLE datadog LOGIN PASSWORD :'datadog_password';
ALTER ROLE datadog SET default_transaction_read_only = on;
GRANT CONNECT ON DATABASE sessions TO datadog;
GRANT USAGE ON SCHEMA public TO datadog;
GRANT SELECT ON TABLE queue_messages, sessions, turns, attempts, provider_usage TO datadog;既存のデプロイコマンドのlayerはそのままにして、最後の-fでこのoverlayだけを加え、--env-fileに上のファイルをもう1つ渡します。次は、ローカルstackのエントリーファイルinfra/compose.ymlの上に加えた例です。サーバーへのインストールでは、infra/compose.ymlの代わりにそのインストールのlayerをそのまま書きます。
docker compose \
--env-file /etc/werft/datadog.env \
-f infra/compose.yml \
-f infra/compose.datadog.yml \
--profile apps up -dこの形を、リポジトリのcomposeファイルでdocker compose configまで確認しました。overlayを加えると、サービス一覧にdatadog-agentが1つ増え、api、scheduler、reconciler、egress-proxy、postgresにDatadogのlabelが付きます。サービス一覧はレンダリングで確認しましたが、labelはinfra/compose.datadog.ymlの内容を読んだもので、レンダリング結果では確認していません。DD_ENVやDD_VERSIONがないと、レンダリングが拒否されます。実際のサーバーでupまで実行し、AgentがDatadogに報告することは確認していません(NOT VERIFIED)。
Agentは、Docker socketとcontainer log directoryをread-onlyでmountし、hostのPID・cgroup namespaceを読みます。DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL=trueで動的なworkerも収集します。compose serviceはservice・env・version labelを受け取ります。動的なworkerのserviceはcontainerのshort-imageから導かれ、envはAgentのグローバルなDD_ENVから、versionはグローバルなDD_TAGSから受け取ります。session_id・turn_idは調査用のログattributeとしてだけ残し、metric tagやfacetにはしません。
シグナルと初期monitor
構造化loggerの元のrecordは、timestamp、level、機械が読むevent、人が読むmessage、任意のfields、context(session_idなど)です。log pipelineはJSONをparseし、以前のrecordにeventがないときだけmessageをfallbackとして使います。詳細な値はfields.*の下にあります。queryのmetric名は、log-metrics.jsonとPostgreSQL custom queryが作る名前です。
| リスク | 現在のシグナル(ログevent・フィールド、DB query、readyz) | Datadog monitor(query・しきい値・ウィンドウ) | アラート時の対応runbook | 計測の空白 |
|---|---|---|---|---|
| interrupt effectが5秒を超える | control.resultのfields.operation:interrupt、effect_ms、outcome、reason_code、control_id → werft.control.effect.duration_ms。段階別の診断には、同じcontrol_idのworker.turn.interrupt.stageを使います | p95 avg(last_5m):p95:werft.control.effect.duration_ms{operation:interrupt} > 5000; unknownの結果 > 0/5m | interrupt後に結果がわからないturn | なし |
| terminate・controlの受け付け遅延 | すべての/v1完了のapi.request.completed(route_template、method、status、duration_ms、request_id)。terminate 202はwerft.terminate.acceptance.duration_msにし、同じrequest_idのcontrol transactionの段階と相関させます | p95 avg(last_5m):p95:werft.terminate.acceptance.duration_ms{*} > 200 | API設定のterminate計測 | なし |
| セッション作成のp95 | api.request.completedのroute_template:/v1/sessions、method:POST、duration_ms → werft.session.create.duration_ms | デプロイ最初の週のp95をdashboardで観察してからしきい値を確定 | API設定 | なし。しきい値の選択は計測の空白と区別します |
| checkpointの失敗 | worker.checkpoint.failed(fields.stage、fields.reason、fields.revision) → werft.checkpoint.failed | sum(last_5m):sum:werft.checkpoint.failed{*}.as_count() > 0 | checkpointの復元が失敗し続けるセッション | なし |
| checkpoint pendingの理由・経過時間 | sessions.checkpoint_pending_reason; custom query werft.checkpoint.pending_age_seconds | max(last_5m):max:werft.checkpoint.pending_age_seconds{*} > 300 | checkpointの復元が失敗し続けるセッション | sessions.updated_atはpending開始の保守的なproxyで、正確な開始時刻はデプロイ後に判断 |
| captureの遅延、PUT数・bytes・manifestサイズ | 成功・拒否・失敗のたびに、worker.checkpoint.resultが1つ、duration_ms、durations_ms、put_count、uploaded_bytes、manifest_bytes、reused_count、conflict_count、outcome、reason_codeを残します。worker.checkpoint.publishedのbundle・untrackedサイズとworker.checkpoint.lateも維持します | capture p95 > 20,000 ms/5m; late count > 0/5m; bundle・untracked > 214,748,364 bytes/15m; manifest > 6,710,886 bytes/15m | checkpointの復元が失敗し続けるセッション | なし |
| S3 5xx・stall | checkpoint結果のoutcome、reason_code、段階別のdurations_msでcaptureの結果は区別しますが、S3の応答そのものは構造化しません | 信頼できるS3 status queryがないため、monitor定義なし | object storeの選び方 | S3のoperation/status/durationはデプロイ後に判断 |
| worker launch/exitの繰り返し | Launching execution failed; intent kept for retry、Execution resource exited right after launch、Launch attempt failed; retrying after a backoff → werft.launch.failed; Execution exited; resource reclaimed、Claimed execution resource vanished; binding released → werft.execution.exited | launch: sum(last_10m):sum:werft.launch.failed{*}.as_count() > 3; exit: sum(last_10m):sum:werft.execution.exited{*}.as_count() > 5 | 起動段階で落ち続けるセッション | なし |
| ストレージ障害後の収束 | Execution launched、上のlaunch/exit event、Orphan session reconciliation completedのfields.requeued_count・fields.blocked_count | 繰り返しlaunch/exitのmonitorで症状は検知 | reconciler・scheduler | 障害の開始からすべてのsessionが収束するまでの時間と、収束していないsessionの数はデプロイ後に判断 |
| lease lost | Expired lease reconciliation completed(fields.fenced_count、fields.ended_count); custom query werft.lease.stale_count | max(last_5m):max:werft.lease.stale_count{*} > 0 | reconciler・scheduler | なし |
| queue oldest age | unclaimedかつvisibleなqueue_messages.created_atの最小値 → werft.queue.oldest_age_seconds | max(last_5m):max:werft.queue.oldest_age_seconds{*} > 30 | reconciler・scheduler | なし |
| readyzの可用率 | Agent HTTP check werft-readyz → http.can_connect | 直近3回のうち失敗、5分のno-data | API設定 | なし |
| provider 429・5xx | proxyはupstreamへの接続失敗だけを記録し、providerのresponse statusは記録しません | 信頼できるstatus queryがないため、monitor定義なし | provider・egressの設定 | providerのstatus・retryの結果はデプロイ後に判断 |
| providerのコスト・fallback pricing | provider_usageの1時間合計 → werft.provider.cost_usd_1h、werft.provider.fallback_pricing_count_1h、werft.provider.unmetered_tokens_1h | cost > 20 USD/1h; fallback count > 0/1h | インストール上限 | なし。コストのしきい値はインストールの予算に合わせて最初の週に必ず調整します |
| disk・inode・XFS quota | Agent hostのsystem.disk.in_use、system.fs.inodes.in_use; 現在はxfs_quotaを手動で確認 | host disk・inode > 0.8 for 10m | worker workspaceの上限と回収 | workspaceごとのXFS project quota使用率のmetricはデプロイ後に判断 |
| legal hold・orphanの増加 | 現在checkpoint inventoryのmetricなし | monitor定義なし | checkpoint objectのversionとhold | inventory metricを実装した後に監視を判断し直します |
| backupの失敗 | scripts/backup.shのexitと運用historyは、DockerのJSON stdoutに入りません | monitor定義なし | バックアップ | backup実行結果の構造化はデプロイ後に判断 |
DB点検queryの契約
infra/datadog/conf.d/postgres.d/conf.yamlのcustom_queriesが正本です。どのqueryもSELECT1つで、tableを変更しません。
- queue oldest age: まだclaimされておらず、すでにvisibleなmessageのうち最も古い
created_atを、DBのclockと比較します。 - checkpoint pending age:
checkpoint_pending_reason IS NOT NULLのsessionのupdated_atのうち最も古い値を使います。checkpointと無関係な同じsessionの更新がこの時刻を動かすことがあるので、正確なSLIではなく下限のproxyです。 outcome_unknown: 直近5分に作られたturns.outcome_unknown = trueのrow数です。- stale lease:
exited・lostでないattemptのうち、lease_expires_at < clock_timestamp()である数です。 - providerのコスト: 直近1時間の
cost_usdの合計と、priced_by = 'fallback'のrow数です。werft.provider.unmetered_tokens_1hは、同じ1時間のpriced_by = 'unmetered'のrowのトークン合計(input・output・cache write・cache read)です。billing: noneprofileはコストが0のまま残るので、有料のupstreamを誤って宣言したときに表に出るのはこのトークン数だけです。monitorは定義しません。正常値がインストールのローカルモデルの使用量に依存するためです。
どのqueryもsession_idを返しません。log-metrics.jsonのgroup-byも、service・envとcardinalityの低い状態だけを使います。session_idは、incidentで元のログやDBを絞り込むときだけ使います。
定義の適用と検証
定義は自動では適用されません。運用者はJSONをレビューしてから、各ファイルのendpointにrequestsの項目を1つずつ適用します。log-facets.jsonは、UIで作るfacetと、作らないhigh-cardinality attributeの一覧です。dashboard.jsonはdashboardのcreate bodyです。すでに適用したmonitor・dashboard・log pipelineは再度createせず、既存のものの名前とquery・filterを新しい定義に合わせて直します。再度createすると、同じ定義が2つになります。
サーバーデプロイで次を確認します。
- 既定のstackをoverlayなしでrender・起動したとき、service一覧と設定が以前と同じである。
- overlayを加えた
docker compose configがDD_ENV・DD_VERSIONの欠落を拒否し、AgentのDocker socket mountがroで、/etc/werft/datadog.envだけを読む。 - Agent statusで、Docker log、
http_check:werft-readyz、PostgreSQL custom queryがすべて成功する。 /readyzを一時的に失敗させて、service checkが変わり、復旧することをサーバーで確認する。実際の長期stack実行とmonitor notificationの配信は、ローカルの検証証拠で代替しません。