feat(ai-env,alerting): reference queries per alert in slo.md, rule expression as alert annotation

第 4 回 V-G1 で LLM が route フィルタのない 5 分窓の p95(0.017 秒)を根拠に
「遅延なし」と結論した。slo.md にアラートごとの基準クエリ(規則と同じ式、
legacy のインスタンス別遅延と要求率を含む)を書き、確かめ直すときは同じ式を
使わせる。各規則の annotations.condition に式をそのまま入れ、AI 側が
「アラート条件が解消したか」を計算できるようにする(Jev の recovering 再定義)。
This commit is contained in:
seon committed 2026-10-09 08:33:22 +09:00
1 parent bfd5a710f7
commit fd08c32501
2 files changed
+22 -1

No files matched your search

+12 -1
View File
@@ -1,4 +1,15 @@
可用性: キャンペーン期間を通じて avg_over_time(probe_success[5m]) >= 99.5%。レイテンシ: api の p95(histogram_quantile(0.95, sum by (le) (rate(demo_http_request_duration_seconds_bucket[5m]))))が 0.5 秒未満。エラー率: 5 分間の 5xx / 全リクエストが 1% 未満。 可用性: キャンペーン期間を通じて avg_over_time(probe_success[5m]) >= 99.5%。レイテンシ: api の p95(histogram_quantile(0.95, sum by (le) (rate(demo_http_request_duration_seconds_bucket{route=~"orders|price"}[5m]))))が 0.5 秒未満。エラー率: 5 分間の 5xx / 全リクエストが 1% 未満。
復旧(t_recover)は、プローブが 12 回連続(3 分)で成功し、かつ 5 分窓のレイテンシとエラー率が SLO の内側に戻ったときにハーネスが宣言する。 復旧(t_recover)は、プローブが 12 回連続(3 分)で成功し、かつ 5 分窓のレイテンシとエラー率が SLO の内側に戻ったときにハーネスが宣言する。
層: 1 = プラットフォーム内部の自動復旧(kubelet の再起動、ReplicaSet、Argo CD selfHeal、MIG autohealing、compose の restart)。2 = あなたの提案 + Discord での人の承認、実行はハーネス。3 = 人だけが行う(不可逆な操作、15 分以内に承認がない場合、確信度 0.5 未満)。 層: 1 = プラットフォーム内部の自動復旧(kubelet の再起動、ReplicaSet、Argo CD selfHeal、MIG autohealing、compose の restart)。2 = あなたの提案 + Discord での人の承認、実行はハーネス。3 = 人だけが行う(不可逆な操作、15 分以内に承認がない場合、確信度 0.5 未満)。
アラートルールと意味: ProbeDown(probe_success == 0 が 1 分、症状のみ)、ApiLatencyHigh(直近 1 分の p95 > 500 ms が 2 分)、ApiErrorRateHigh(5xx > 1% が 3 分)、PodCrashLooping(5 分で 3 回以上の再起動。まず層 1、5 分後に層 2)、LegacyUnhealthy(up な legacy-api インスタンスが 2 未満。まず autohealing、10 分後に層 2)、DbReplicationLag(遅延 > 60 秒、または replay が一時停止)、ApiMemoryPressure(api コンテナのメモリが limit の 80% 超を 1 分継続。グレーゾーン、承認後に rollout restart)、DbPrimaryDown(TCP 5432 の失敗が 1 分)、GitOpsDrift(OutOfSync が 5 分。selfHeal が処理する)。 アラートルールと意味: ProbeDown(probe_success == 0 が 1 分、症状のみ)、ApiLatencyHigh(直近 1 分の p95 > 500 ms が 2 分)、ApiErrorRateHigh(5xx > 1% が 3 分)、PodCrashLooping(5 分で 3 回以上の再起動。まず層 1、5 分後に層 2)、LegacyUnhealthy(up な legacy-api インスタンスが 2 未満。まず autohealing、10 分後に層 2)、DbReplicationLag(遅延 > 60 秒、または replay が一時停止)、ApiMemoryPressure(api コンテナのメモリが limit の 80% 超を 1 分継続。グレーゾーン、承認後に rollout restart)、DbPrimaryDown(TCP 5432 の失敗が 1 分)、GitOpsDrift(OutOfSync が 5 分。selfHeal が処理する)。
アラートを確かめ直すときは、必ずアラート規則と同じ式(基準クエリ)を使う。route フィルタを外した式は healthz の速い要求で希釈され、遅延を見逃す(第 4 回 V-G1 の誤診)。基準クエリ:
- ProbeDown: probe_success{job="blackbox",target="alb"}
- ApiLatencyHigh: histogram_quantile(0.95, sum by (le) (rate(demo_http_request_duration_seconds_bucket{route=~"orders|price"}[1m])))。遅延の所在を分ける: api→legacy の上流遅延は histogram_quantile(0.95, sum by (le) (rate(demo_legacy_request_duration_seconds_bucket[1m])))、legacy のインスタンス別は histogram_quantile(0.95, sum by (instance, le) (rate(legacy_http_request_duration_seconds_bucket[1m])))、インスタンス別の要求率は sum by (instance) (rate(legacy_http_requests_total{route!="healthz"}[2m]))。1 分窓が高く 5 分窓が低いのは ILB が接続を別インスタンスへ逃がした直後で、遅いインスタンスが残っている限り原因は消えていない(network_latency_legacy、処置は mig.recreate_instance、対象はそのインスタンス名 legacy-xxxx)。
- ApiErrorRateHigh: sum(rate(demo_http_requests_total{route=~"orders|price",status=~"5.."}[5m])) / sum(rate(demo_http_requests_total{route=~"orders|price"}[5m]))
- ApiMemoryPressure: max by (pod) (container_memory_working_set_bytes{namespace="demo",container="api"}) / on (pod) max by (pod) (kube_pod_container_resource_limits{namespace="demo",container="api",resource="memory"})
- PodCrashLooping: increase(kube_pod_container_status_restarts_total{namespace="demo"}[5m])
- LegacyUnhealthy: up{job="legacy-api"}
- DbReplicationLag: max(pg_replication_lag_seconds) と max(pg_is_wal_replay_paused)
- DbPrimaryDown: probe_success{job="blackbox",target="db-primary"}
- GitOpsDrift: argocd_app_info{sync_status!="Synced"}
アラートの annotations.condition にも規則の式がそのまま入っている。
@@ -17,6 +17,7 @@ groups:
layer: '2' layer: '2'
annotations: annotations:
summary: ALB synthetic probe failing (symptom alert, cause unknown) summary: ALB synthetic probe failing (symptom alert, cause unknown)
condition: max(probe_success{job="blackbox",target="alb"}) == bool 0
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -48,6 +49,7 @@ groups:
layer: '2' layer: '2'
annotations: annotations:
summary: api p95 over the last minute above 500 ms for 2 minutes summary: api p95 over the last minute above 500 ms for 2 minutes
condition: histogram_quantile(0.95, sum by (le) (rate(demo_http_request_duration_seconds_bucket{route=~"orders|price"}[1m]))) > bool 0.5
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -79,6 +81,7 @@ groups:
layer: '2' layer: '2'
annotations: annotations:
summary: demo api 5xx ratio above 1% (grey zone) summary: demo api 5xx ratio above 1% (grey zone)
condition: (sum(rate(demo_http_requests_total{status=~"5.."}[5m])) / sum(rate(demo_http_requests_total[5m]))) > bool 0.01
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -111,6 +114,7 @@ groups:
signature: pod_crashloop signature: pod_crashloop
annotations: annotations:
summary: container restarted 3+ times in 5m (kubelet is handling; escalate after 5m) summary: container restarted 3+ times in 5m (kubelet is handling; escalate after 5m)
condition: max by (pod) (increase(kube_pod_container_status_restarts_total{namespace="demo"}[5m])) >= bool 3
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -143,6 +147,7 @@ groups:
signature: legacy_unhealthy signature: legacy_unhealthy
annotations: annotations:
summary: fewer than 2 healthy legacy-api instances (MIG autohealing is handling; escalate after 10m) summary: fewer than 2 healthy legacy-api instances (MIG autohealing is handling; escalate after 10m)
condition: count(up{job="legacy-api"} == 1) < bool 2
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -174,6 +179,7 @@ groups:
layer: '2' layer: '2'
annotations: annotations:
summary: replica lag above 60s or WAL replay paused (grey zone, small SLO impact) summary: replica lag above 60s or WAL replay paused (grey zone, small SLO impact)
condition: clamp_max((max(pg_replication_lag_seconds) > bool 60) + (max(pg_is_wal_replay_paused) == bool 1), 1)
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -205,6 +211,7 @@ groups:
layer: '2' layer: '2'
annotations: annotations:
summary: db-primary 5432 unreachable (layer 2 diagnosis, layer 3 expected) summary: db-primary 5432 unreachable (layer 2 diagnosis, layer 3 expected)
condition: max(probe_success{job="blackbox",target="db-primary"}) == bool 0
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -237,6 +244,7 @@ groups:
signature: gitops_drift signature: gitops_drift
annotations: annotations:
summary: Argo CD application OutOfSync for 5m (selfHeal is handling; recorded) summary: Argo CD application OutOfSync for 5m (selfHeal is handling; recorded)
condition: max(argocd_app_info{sync_status!="Synced"}) == bool 1
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange:
@@ -268,6 +276,8 @@ groups:
layer: '2' layer: '2'
annotations: annotations:
summary: an api container holds more than 80% of its memory limit for 1 minute (grey zone; rollout restart after approval) summary: an api container holds more than 80% of its memory limit for 1 minute (grey zone; rollout restart after approval)
condition: max by (pod) (container_memory_working_set_bytes{namespace="demo",container="api"}) / on (pod) max by (pod) (kube_pod_container_resource_limits{namespace="demo",container="api",resource="memory"})
> bool 0.8
data: data:
- refId: A - refId: A
relativeTimeRange: relativeTimeRange: