リファレンスと解説従来の運用ドキュメント

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.env

Agent 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/5minterrupt後に結果がわからない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{*} > 200API設定のterminate計測なし
セッション作成のp95api.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.failedsum(last_5m):sum:werft.checkpoint.failed{*}.as_count() > 0checkpointの復元が失敗し続けるセッションなし
checkpoint pendingの理由・経過時間sessions.checkpoint_pending_reason; custom query werft.checkpoint.pending_age_secondsmax(last_5m):max:werft.checkpoint.pending_age_seconds{*} > 300checkpointの復元が失敗し続けるセッション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/15mcheckpointの復元が失敗し続けるセッションなし
S3 5xx・stallcheckpoint結果の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.exitedlaunch: 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 lostExpired lease reconciliation completed(fields.fenced_count、fields.ended_count); custom query werft.lease.stale_countmax(last_5m):max:werft.lease.stale_count{*} > 0reconciler・schedulerなし
queue oldest ageunclaimedかつvisibleなqueue_messages.created_atの最小値 → werft.queue.oldest_age_secondsmax(last_5m):max:werft.queue.oldest_age_seconds{*} > 30reconciler・schedulerなし
readyzの可用率Agent HTTP check werft-readyz → http.can_connect直近3回のうち失敗、5分のno-dataAPI設定なし
provider 429・5xxproxyはupstreamへの接続失敗だけを記録し、providerのresponse statusは記録しません信頼できるstatus queryがないため、monitor定義なしprovider・egressの設定providerのstatus・retryの結果はデプロイ後に判断
providerのコスト・fallback pricingprovider_usageの1時間合計 → werft.provider.cost_usd_1h、werft.provider.fallback_pricing_count_1h、werft.provider.unmetered_tokens_1hcost > 20 USD/1h; fallback count > 0/1hインストール上限なし。コストのしきい値はインストールの予算に合わせて最初の週に必ず調整します
disk・inode・XFS quotaAgent hostのsystem.disk.in_use、system.fs.inodes.in_use; 現在はxfs_quotaを手動で確認host disk・inode > 0.8 for 10mworker workspaceの上限と回収workspaceごとのXFS project quota使用率のmetricはデプロイ後に判断
legal hold・orphanの増加現在checkpoint inventoryのmetricなしmonitor定義なしcheckpoint objectのversionとholdinventory 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: none profileはコストが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つになります。

サーバーデプロイで次を確認します。

  1. 既定のstackをoverlayなしでrender・起動したとき、service一覧と設定が以前と同じである。
  2. overlayを加えたdocker compose configがDD_ENV・DD_VERSIONの欠落を拒否し、AgentのDocker socket mountがroで、/etc/werft/datadog.envだけを読む。
  3. Agent statusで、Docker log、http_check:werft-readyz、PostgreSQL custom queryがすべて成功する。
  4. /readyzを一時的に失敗させて、service checkが変わり、復旧することをサーバーで確認する。実際の長期stack実行とmonitor notificationの配信は、ローカルの検証証拠で代替しません。

このページ