---
title: デプロイ検出の仕組みと、スパンに必要な情報
description: >-
  sigiro がデプロイのために読み取る属性は 1 つだけです — スパンのリソース上にある service.version
  です。このページでは、バージョンがどのようにデプロイイベントになるのか、sigiro
  がどのように容疑デプロイを選ぶのか、そしてサービスがバージョンをまったく送信しない場合に何が得られるのかを説明します。
sidebar:
  order: 4
---
診断は容疑デプロイを名指しできます: _incident ~14:30 on service 'checkout':
… ; suspect deploy: version 1.4.2 first seen at 14:29_。これは強い主張であり、
読み手がその根拠を問うのは当然です。

その根拠は、1 か所にある 1 つの属性です。このページでは、その属性を明示し、
sigiro がデプロイと定常状態をどのように区別するかを述べ、あるデプロイがどのように
容疑となるかを説明し、その属性が欠けている場合に何が得られるかを示します。
最後の部分が最も重要です。欠落は無言だからです。

## 1 つの属性、1 か所

sigiro は **スパンのリソース属性** から `service.version` を読み取ります。

これがすべての情報源です。sigiro はデプロイのために他のフィールドを一切読み取りません:

| デプロイのために読み取らないもの | 理由 |
| --- | --- |
| `deployment.environment`、`deployment.*` | どのクエリもこれらを読み取りません |
| `git.commit.sha`、`vcs.*` | どのクエリもこれらを読み取りません |
| ログ、メトリクス、プロファイル上の `service.version` | sigiro は `sigiro_spans` のみをスキャンします |
| CI Webhook、デプロイ API、リリースフィード | sigiro には OTLP 以外の取り込み経路がありません |
| Kubernetes API サーバー | sigiro は決して接続しません |

リソース属性は OTLP 経由で到着し、`sigiro_spans` の `resource_attributes` カラムに
JSON 文字列としてそのまま格納されます。取り込み時に専用のカラムを持つリソース属性は
3 つ — `service.name`、`service.namespace`、`service.instance.id` です。
`service.version` はそのうちの 1 つではないため、sigiro はクエリのたびに JSON から
読み出します。

「スパンのみ」であることから 2 つの帰結が生じます。ログをエクスポートしていても
スパンをエクスポートしていないサービスは、どれほど優れたログであってもデプロイイベントを
生成しません。あるプロセスからはスパンをエクスポートし、別のプロセスからはしていない
サービスは、計装されたプロセスが新バージョンで再起動したときにのみデプロイを報告します。

値そのものは sigiro にとって不透明です。semver 文字列、git SHA、ビルド番号、日付は
すべて同じように機能します。sigiro は 2 つの文字列の等価性を比較するだけで、
どちらも解析しないからです。sigiro はバージョンから順序を導出しないため、
アップグレードとロールバックを区別できません。

## デプロイとは、ベースラインになかったバージョンのこと

sigiro には読み取るべきデプロイのタイムスタンプがないため、それを導出します。
デプロイイベントとは、診断ウィンドウ内のスパンに現れ、ベースラインウィンドウ内の
**いずれの** スパンにも現れない `service.version` の値です。

ベースラインウィンドウは診断ウィンドウの 4 倍の長さで、診断ウィンドウの開始地点で
終了します。デフォルトの診断ウィンドウは直近 15 分間なので、デフォルトのベースラインは
その 1 時間前までとなります。

各デプロイイベントは以下を持ちます:

- `event_type` — 文字列リテラル `deploy`
- `detected_at` — ウィンドウ内でそのバージョンを持つ最も早いスパンのタイムスタンプ。
  これは sigiro がそのバージョンを最初に _見た_ 時刻であり、デプロイが開始された
  時刻ではありません
- `description` — `version 1.4.2 first seen`

ベースラインとの比較こそが重要な半分であり、これは現実の失敗を解消します。これがないと
「first seen」はウィンドウの最初の行を意味するため、あらゆる正常なサービスのあらゆる診断が
ウィンドウの開始時点でデプロイを報告してしまいます。そのイベントは常に利用可能で、
常にインシデントと時間的に隣接しており、それを読んだエージェントはそれを原因と見なします。
恒久的な誤った手がかりは、手がかりがないことよりも悪いのです。したがって、ウィンドウ開始前に
すでに稼働していたバージョンは定常状態として扱われます。

さらに 5 つの帰結が直接生じ、そのいずれもが誰かを驚かせます:

- **一定のバージョンは何も生成しません。** すべてのビルドが `service.version=1.0.0` を
  出荷する場合、sigiro はデプロイイベントを一度だけ報告し、その後は二度と報告しません。
  デプロイを可視化するには、各リリースに異なる値を与えてください。
- **複数の新バージョンは複数のイベントを生成します。** クエリはバージョンごとに
  グループ化するため、3 つの新バージョンを含むウィンドウは 3 つのデプロイイベントを返します。
- **ロールバックはデプロイとして読み取られます。** 旧バージョンはベースラインウィンドウに
  存在しないため、この定義では新規となります。
- **テレメトリの欠落はデプロイとして読み取られます。** サービスがベースラインウィンドウで
  スパンを送信していなかった場合、ベースライン集合は空となり、ウィンドウ内のすべての
  バージョンが新規になります。サービスが新規である場合や静かだった場合は、ウィンドウ開始時点の
  デプロイを慎重に読み取ってください。
- **より広いウィンドウはより過去まで遡ります。** sigiro は指定されたウィンドウから
  ベースラインを導出するため、6 時間の診断は直前の 24 時間と比較されます。

## Kubernetes イベントはログのテキストから得られます

同じ `events` 配列は 2 つ目のイベント種別 `k8s_event` も含み、こちらは情報源が異なります。

sigiro は、ウィンドウ内のサービスのログの `body` カラムを、5 つの固定された部分文字列
`OOMKilled`、`Unhealthy`、`BackOff`、`FailedScheduling`、`ScalingReplicaSet` について
スキャンします。マッチは大文字と小文字を区別する単純な部分文字列マッチです。description は
ログ本文全体であり、sigiro は 1 回の診断につき最大 20 件までを返します。

つまり、これは Kubernetes インテグレーションではありません。sigiro は API サーバーと
通信することは決してありません。これらのイベントが見えるのは、診断対象のサービスと同じ
`service.name` の下で、何かがクラスターイベントを OTLP ログへ転送している場合だけです。
イベントを監視してログとしてエクスポートするコレクターが通常の構成です。何も転送していない
場合、配列にはデプロイイベントのみが入ります。

`k8s_event` が容疑になることはありません。対象となるのは種別 `deploy` のイベントだけです。

## あるデプロイが容疑となるまで

これを決定するルールは 2 つあり、いずれも検出器自身の 5 分バケットに由来します。

第一に、容疑が付くのは **インシデント** だけです。他のどのシフトとも相関しない単一の
シフトは単一シグナル項目のままで、デプロイフィールドをまったく持ちません。同じバケット
または隣接するバケット内の 2 つ以上のシフトはインシデントに統合され、その項目だけが
デプロイを探します。[ダッシュボードではなくエビデンスについて](/docs/explanation/evidence)
では、シフトがそのように相関する理由を説明しています。

第二に、デプロイが条件を満たすのは、そのバケットがインシデント自身のバケット範囲内にある場合、
または最初のシフトの 1 つ前のバケットにある場合です。この 1 バケット分の余裕は許容誤差ではなく
算術上の必然です。14:30 のバケットで検出されたシフトを引き起こした 14:29 のデプロイは、
構造上 1 バケット前になります。複数のデプロイが条件を満たす場合は、インシデントの開始時刻に
最も近いものが選ばれます。

選ばれたものは 2 か所に現れます。インシデント上の `deploy` オブジェクトとしてと、
項目サマリーの末尾の節としてです。その他のデプロイイベントはすべてサービスの `events`
配列に残り、sigiro はこれを時刻順にソートし、フィルタリングは一切行いません。したがって、
比較に敗れたデプロイもレスポンス内に残っており、読むことができます。

sigiro が主張するのは時間的な相関のみで、それ以上ではありません。_容疑_ という語は
意図的に使われています。

## サービスがバージョンを設定していない場合に起こること

端的に言えば、デプロイイベントは得られず、sigiro はそれについて何も伝えません。

クエリは `service.version` が null の行を除外するため、この属性を一度も設定しない
サービスはデプロイイベントに寄与しません。その場合 `events` 配列には Kubernetes イベント
だけが入るか、空になります。すべてのインシデントは `deploy: null` を持ち、サマリーは
容疑の節なしで終わります。

警告する項目はありません。sigiro は `k8s.namespace.name` と `k8s.deployment.name` が
欠けている場合に種別 `missing_resource_attributes` の項目を出しますが、その項目は
`service.version` については何も述べません。バージョンに対応するものは存在しません。
劣化は無言です。

これは、レスポンスのうち額面どおりに読めない唯一の部分です。デプロイイベントのない
ウィンドウは、まったく異なる 2 つの状況で同じに見えます。デプロイが起きなかった場合と、
どのプロセスも `service.version` を設定していない場合です。レスポンスはこの 2 つを
区別しません。

次のクエリはこの 2 つを区別します:

```sql
SELECT DISTINCT resource_attributes::JSON->>'service.version' AS version
FROM sigiro_spans
WHERE service_name = 'checkout'
  AND timestamp > now() - INTERVAL '24 hours';
```

結果は次のように読んでください:

- 1 行のみで、その値が `NULL` — 何もこの属性を設定していません。sigiro はこのサービスに
  ついてデプロイを報告することが決してできません。
- 値を持つ 1 行のみで、何日も変化していない — 何かがこの属性を設定していますが、値が
  決して変わりません。sigiro はその値を最初に見たときにデプロイを報告し、それ以降は
  何も報告しません。
- 複数行 — このサービスではデプロイ検出が機能しています。

サービスの OpenTelemetry リソースにこの属性を設定し、各リリースに異なる値を与えてください。
[エージェントでコードを計装する](/docs/how-to/install-with-ai) では、リソースの設定
そのものを扱っています。

## 次に読むもの

- [ダッシュボードではなくエビデンスについて](/docs/explanation/evidence) — シフトが
  どのようにインシデントになるのか、そしてなぜすべての行がクエリを伴うのか
- [テーブルと、それらが記述するマシンについて](/docs/explanation/tables) —
  `resource_attributes` はどこにあるのか、どのテーブルがどの問いに答えるのか
- [API リファレンス](/docs/reference) — `DerivedEvent` と `Incident` のフィールドの全容
