跳转至

可观测性 SSOT (采集 · 告警 · 报告)

SSOT Key: ops.obs 核心定义: infra2 可观测性的唯一 owner——遥测采集(logs/metrics/traces)、告警(规则/分级/飞书路由)、 报告/可用率账本(正向证明),以及把这三者统一起来的时间尺度分层模型

收敛自原 SSOT key ops.alerting + ops.availability_ledger(已并入本文)。watchdog-signals.yaml 作为信号数据 registry 保留;遥测标识(env identity)归 core.environments.md

第一性原理(本文的脊梁):告警 = 事件驱动(真出事才发);报告 = 时间驱动(周期发)。 二者绝不混——尤其不能周期性地发告警。详见 §2。


1. 真理来源 (The Source)

维度 物理位置 (SSOT) 说明
采集 - 存储 platform/03.clickhouse ClickHouse + ZooKeeper
采集 - 应用 platform/11.signoz Query Service + Frontend + OTLP Collector
告警 - 规则 SigNoz Alert Manager + finance_report/finance_report/observability/alert_rules.json(config-as-code) 告警规则
告警 - 通知 platform/12.alerting SigNoz webhook → Feishu custom bot / app bot bridge;in-band probe runner
告警 - 密钥源头 1Password platform/{env}/alerting → 运行时镜像 Vault secret/platform/{env}/alerting Feishu 凭据 + 可选 bridge basic auth
带外 watchdog cloudflare/infra-watchdog(主,边缘 30min)+ .github/workflows/ops-checks.yml(GitHub 兜底,日级) 整机/整栈失联检测
信号清单 watchdog-signals.yaml 按信号(非组件)追踪 watchdog 归属
报告 - 账本 Cloudflare KV(热 21 天)+ R2(冷长期)·libs/availability_ledger.py(聚合)·tools/stability_report.py(周报) 正向证明
部署指南 Infra-007 SigNoz 安装

In-band 告警路径恒为:component/app → OTLP Collector → SigNoz → platform/12.alerting → Feishu/Lark。 带外检测独立于 VPS(SigNoz 与 bridge 都在单台机器上,会和宿主一起挂),故走 Cloudflare 边缘 cron 直发 Feishu。


2. 信号模型与时间尺度分层 (Signal model & cadence tiers)

统一框架。立论与 MECE 论证见 issue #425;本节是其 SSOT 落地。

不变式: - ALERT(事件驱动)——只在真故障时发;cadence = f(故障时间尺度)。 - REPORT(时间驱动)——周期性汇总;cadence = 人的复盘节奏。 - 铁律:任何定时器发出的东西都是报告,绝不是告警。 推论:一份报告自身的成功送达,就是投递链路的自证——无需单独的合成告警。

分层(cadence = 1 / 故障时间尺度;每个 check 落且只落一档 = 它"在造成伤害前还能抓住"的最粗 cadence):

尺度 性质 干什么 为什么这个频率
分钟级 告警 真 liveness / 写路径 / 公网 5xx / Vault sealed —— 分钟内伤用户的 用户面故障第 1 分钟就疼 → 分钟级抓
小时级 告警 + 带外兜底 慢失效:证书/token 临期(TTL 6/24h)、备份新鲜度、路由创建能力;整机失联(Cloudflare 边缘 30min) 小时尺度发展;整机挂也快不过人响应
天级 报告 健康日报(探针绿/红、今日 fire/resolve、备份新鲜度、drift/未发布增量)——其送达即投递自证;deploy-v2 canary 投递配置/drift 在天尺度变;人天级复盘
月级 报告/演练 DR 全量恢复演练(不可逆数据兜底)、凭据轮换审计、容量趋势、SLA 月度 rollup 重、且守的东西变得慢,但必须真跑

横切不变式:≤小时 = 告警,≥天 = 报告;告警/报告的分界线就是"天"。


3. 告警分级 (Severity)

等级 颜色 响应时效 定义
P0 (Critical) 🔴 Red 立即 (24x7) 核心服务不可用 (Vault, SSO, DB Down)
P1 (Error) 🟠 Orange 30分钟 部分功能受损,核心链路仍通
P2 (Warning) 🟡 Yellow 工作日 资源使用率高,非关键错误

4. 采集 (Collection / OTLP)

4.1 架构与数据流

graph LR
    Apps[Applications] -->|OTLP| Collector[OTLP Collector]
    Collector -->|Export| ClickHouse[(ClickHouse)]
    QueryService[Query Service] -->|Query| ClickHouse
    Frontend[Web UI] -->|API| QueryService
    QueryService -->|Alert webhook| Alerting[Feishu Alert Bridge]
    Alerting -->|Text message| Feishu[Feishu Group]
组件 位置 端口 用途
ClickHouse platform/03.clickhouse 9000, 8123 (内部) 时序数据存储
ZooKeeper platform/03.clickhouse 2181 (内部) 集群协调
OTLP Collector platform/11.signoz 4317, 4318(内部) 数据采集
Query Service platform/11.signoz 8080 (内部) 查询引擎
Frontend platform/11.signoz 3301 (Traefik) Web 界面
Alert Bridge platform/12.alerting 8080 (内部) SigNoz 告警转飞书

数据流:应用 OTLP → Collector(4317/4318, Docker 网络内)→ ClickHouse → Query Service → Frontend (https://signoz${ENV_DOMAIN_SUFFIX}.${INTERNAL_DOMAIN});告警 SigNoz Alertmanager webhook → platform-alerting${ENV_SUFFIX} → Feishu。

采集设计约束:OTLP SDK 埋点 · 结构化(JSON)日志 · 发送前脱敏(密码/Token/PII)· 统一 OTLP 协议。 禁止:日志/trace 输出原始敏感信息 · 私有协议 · 绕过 Collector 直写 ClickHouse。

4.2 应用接入 OTLP

前置:SigNoz 已部署健康;应用在 dokploy-network;端点 platform-signoz-otel-collector:4317(gRPC)/:4318(HTTP),仅 Docker 网络内、不对外暴露

单一全局实例:SigNoz 是 prod_only 单实例。preview/staging/production 全部打到这个无后缀 collector,靠 deployment.environment.name 区分环境(无 per-env collector)。标识规则见 core.environments.md

变量 说明 示例
OTEL_EXPORTER_OTLP_ENDPOINT OTLP HTTP 端点(所有环境无后缀) http://platform-signoz-otel-collector:4318
OTEL_SERVICE_NAME 服务名 finance-report-backend
OTEL_RESOURCE_ATTRIBUTES ServiceIdentity 渲染的完整资源身份 deployment.environment.name=production,infra.service.id=finance_report/app,service.version=<version>,infra.iac.ref=<sha>

表层别名与底层 commit 由 infra2 部署时签发,应用只消费、对缺失 fast-fail。

4.3 finance_report 接入(BE + 浏览器 FE,Infra-014)

后端(Docker 网络内 OTLP HTTP)由 10.app/secrets.ctmpl / preview/secrets.ctmpl 按环境渲染 OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_SERVICE_NAME=finance-report-backend / 由部署入口签发的 OTEL_RESOURCE_ATTRIBUTES。Vault template 只转交进程环境;不得从 Vault secret 覆盖服务、环境、版本或 IaC 身份。迁移期 payload 同时含 deployment.environment.name=<alias> 与旧 deployment.environment=<alias>

浏览器前端走唯一公网 ingest otel.${INTERNAL_DOMAIN}(§4.4),运行时(非 build-time)env 注入 NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.${INTERNAL_DOMAIN}/v1/tracesNEXT_PUBLIC_DEPLOYMENT_ENVIRONMENT=${ENV}NEXT_PUBLIC_GIT_SHA=${GIT_COMMIT_SHA}(promote-not-rebuild:同一镜像跨环境提升保持环境无关)。

4.4 公网浏览器 OTLP ingest:otel.${INTERNAL_DOMAIN}(Infra-014)

collector 4317/4318 仅 expose 于 Docker 网络、永不 publish。唯一公网面是 Dokploy 托管域名 otel.${INTERNAL_DOMAIN}:4318(SigNozDeployer.composing() 通过 ensure_domains(..., service_name="otel-collector") 注册,无手写 Traefik 标签)。

没有 bearer token:浏览器无法保管秘密,下发到页面的静态 token 不是凭据。决策记录:

方案 想法 为何否决
A. 静态 bearer(#360 初版) 给公网 ingest 加"凭据"门槛 浏览器无法保密;token 进 JS 即被 DevTools 拿到 → 假凭据、只是障眼法
B. CORS 门控 + collector 限额(现状) 承认公网 ingest 本质不可鉴权,约束滥用而非鉴权 选中

⚠️ CORS 不是鉴权:它只约束浏览器跨域,挡不住 curl/脚本直接 POST。这是有意为之的未鉴权公网 ingest,靠 collector memory_limiter 限额 + 边缘按 IP 限流(TODO,须 Dokploy 托管 Traefik ratelimit,禁手写标签)兜底。CORS 允许列表在 otel-collector-config.yaml,须与 FE 域名同步。otel.${INTERNAL_DOMAIN} 在泛域名内,无需新增 DNS。

4.5 查询 + synthetic round-trip(分钟级,采集自证)

  • 查询(勿重造):SigNoz invoke signoz.shared.query-logs / list-services(key 在 Vault secret/platform/<env>/signoz);OpenPanel 查询 CLI 在 app 仓库 common/observability/openpanel_query.py(本仓库只引用)。
  • synthetic round-trip(infra-probe-runner,写读探针节流):
  • signoz-roundtrip:每 5min 写一条 OTLP log,再从 signoz_logs.distributed_logs_v2 按 nonce 查回 → 证 collector→ClickHouse ingest/storage 可用。
  • openpanel-roundtrip:每 5min 向 OpenPanel /track 写,再从 openpanel.events 查回 → 证 API→worker/storage 可用。
  • 窗口由 OBS_ROUNDTRIP_INTERVAL_SECONDS / OBS_ROUNDTRIP_QUERY_WAIT_SECONDS 控制;失败作 InfraServiceProbeFailed 进 bridge。

4.6 finance_report 告警/仪表盘 config-as-code(#373)

定义签入 finance_report/finance_report/observability/(alert_rules.jsonFinanceReportBackendErrorLogs + RED/business 规则;dashboard.json;shared_tasks.py),不在 UI 手点;声明式 apply 见 SOP-004B/C 与 ops.pipeline.md(apply 折进 tag reconcile 的目标态)。


5. 告警覆盖目录 (Alert Coverage Catalog)

层级编号沿用 core.md#层级定义(L1 Bootstrap / L2 Platform),L3 为应用层。

Layer Component Signal Severity Status
L1 Bootstrap 1Password Connect /health not active or sync not active P0 Live (op-connect-http)
L1 Bootstrap Vault sealed / unreachable / token validation fails P0 Live probe + vault audit
L1 Bootstrap IaC Runner /health fails before deploy webhook P1 Live (iac-runner-http)
L1 Bootstrap Dokploy deployment control-plane API/UI unreachable or deploy webhooks fail; app health alerts remain app-owned P1 Live probe
Cross-cutting Docker container health any container unhealthy/starting/Restarting outside a deploy window P0/P1 Out-of-band watchdog SSH
L2 Platform platform Postgres TCP readiness fails / restart loop P0 Live probe
L2 Platform platform Redis TCP readiness fails / restart loop P1 Live probe
L2 Platform ClickHouse data dir unwritable / ingestion broken P0 Write-path healthcheck + signoz-roundtrip
L2 Platform MinIO live endpoint unavailable P1 Live probe
L2 Platform Authentik health endpoint fails P0 Live probe
L2 Platform SigNoz frontend/query fails or synthetic OTLP nonce cannot be queried back P0 signoz-internal-http, otel-collector-http, signoz-roundtrip
L2 Platform Alert Bridge /health fails / Feishu unreachable P0 alert-bridge-http, lark-delivery-http + out-of-band bridge health
L2 Platform OpenPanel API /healthcheck fails or synthetic /track nonce not queryable P1 openpanel-api-http, openpanel-roundtrip
L2 Platform OpenPanel ClickHouse (op-ch) data dir unwritable / event store broken P1 Write-path healthcheck + openpanel-roundtrip
L2 Platform OpenPanel Worker / Dashboard /healthcheck / /api/healthcheck fails P1 / P2 Live probes
L2 Platform Portal / Prefect frontend / server-health unavailable P2 / P1 Planned
L3 Finance Report fr-postgres / fr-redis app db / cache health fails P0 / P1 Planned
L3 Finance Report fr-app backend OTEL ERROR/FATAL > 0 over 5m P1 code (FinanceReportBackendErrorLogs)
L3 Finance Report fr-app backend RED SLO: 5xx > 5% 5m / p95 > 1500ms P0/P1 code (FinanceReportHigh5xxRate, FinanceReportP95LatencyHigh)
L3 Finance Report fr-app backend business anomaly: parse spike / reconciliation / rate-limit / async failure P1/P2 code (FinanceReport{StatementParseFailureSpike,ReconciliationAnomaly,RateLimitSaturation,AsyncTaskFailures})
L3 Finance Report fr-app public route report[-staging].zitian.party/ (web) or /api/health from Cloudflare P0 prod / P1 staging Cloudflare out-of-band watchdog
Cross-cutting Vault app tokens / rendered env missing / malformed / invalid / low-TTL / <no value> P0/P1 Docker healthcheck + vault-audit.self-refresh
Cross-cutting Backup freshness latest off-host backup missing/stale/empty/no-checksum P1 backup manifest verifier
Cross-cutting Infra2 host reachability / probe heartbeat public endpoints fail / probe runner stops heartbeat P0/P1 Cloudflare out-of-band watchdog
Cross-cutting SSH host diagnostics external SSH bridge health fails P0 GitHub fallback watchdog
Cross-cutting Deploy queue 部署卡在 running 超过 ceiling(默认 30min;单并发 FIFO 会阻塞所有后续部署) P0 Live (DeployQueueStuck,probe-runner 常驻进程内的 ResidentWatcher 插件 libs/deploy_queue_guard.py,#543 单 sidecar 合并;观测默认开,DEPLOY_GUARD_REMEDIATE=1 才 opt-in 走 Dokploy API kill/clean + 复查升级,绝不直接动 Redis/BullMQ)

设计约束:告警含 actionable runbook 链接 · 聚合避免风暴 · Feishu 凭据只在 1Password(Vault 仅运行时镜像)· SigNoz webhook 只指向内部 bridge URL。 禁止:为瞬时波动指标设 P0 · 忽略 Critical · SigNoz webhook 直指飞书自定义机器人。


6. 报告与可用率账本 (Reporting & Availability Ledger)

故障流告警证明不了"它一直是好的"。账本是闭环的正向一半:成功也记,且绝不能把降级信号报成健康

  • 为何外置(KV/R2 而非 SigNoz):SigNoz 与 bridge 都在单台 VPS,度量不了自己宿主的可用率。账本必须活在比被测对象更可靠的层(Cloudflare)。
  • 记账:worker.js recordLedger 每次 cron 把各信号 ok/fail 累加进当日一个聚合 rollup(绝不一信号一键,否则击穿 KV 免费写配额→静默假死);跨天结算的昨日写入 R2(S3 标准、静态凭据、与备份同后端、Worker 原生 binding,无需第二套同步)。
  • 热 21 天 KV ledger:YYYY-MM-DD/ledger//status/周报;冷长期 R2 watchdog-ledger/YYYY-MM-DD.json
  • 聚合/算 uptime 只在 libs/availability_ledger.py(纯函数,CLI 与测试共用);R2/KV 缺失时安全降级 no-op,部署不挂。
  • 周报:tools/stability_report.py(弱 CLI)读 /ledger → Lark 正向证明,需 INFRA2_WATCHDOG_LEDGER_URL
  • 禁止:per-signal-per-run 建 KV 键 · 把 fail>0 计入 100%/perfect · 信任畸形 day/signal 抬高可用率。

天级日报(目标态,#425 T3):统一健康日报(探针绿/红、今日 fire/resolve、备份新鲜度、drift)发 Feishu,其送达即投递自证;"投递真断了"的硬信号留给独立带外 watchdog。6h 合成 alert-delivery-canary 已退役(它把投递自证做成了周期性告警);当前 bridge→Feishu 路径由 lark-delivery-http(配置有效 + Feishu 可达,不真发)、带外 watchdog 的 bridge /health、日报自身投递、以及真实告警共同覆盖。


7. 标准操作程序 (Playbooks)

SOP-001: 响应 P0 告警

确认影响范围 → 基础设施故障参考 Recovery SSOT → 状态页更新 Incident。

SOP-002: 接入飞书自定义机器人通道

  1. 飞书群建自定义机器人,复制 webhook URL。
  2. 写 1Password root vars + setup-approle:
    uv run invoke env.set FEISHU_WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/<token> --project=platform --env=production --service=alerting --credential-type=root_vars
    uv run invoke vault.setup-approle --project=platform --service=alerting
    
  3. 部署 bridge:uv run python -m tools.deploy_v2 --service platform/alerting --type prod --iac-ref vX.Y.Z --domain zitian.party --code-reviewedinvoke alerting.status
  4. 建 SigNoz channel:invoke signoz.shared.create-api-keyinvoke alerting.create-signoz-channel
  5. 测试:invoke alerting.test-feishu --message="Infra2 alert test"

SOP-003: 接入飞书 App Bot 通道

开放平台启用机器人 + 发布 im:message 权限 + 拿 chat_id,写 1Password root vars(ALERT_DELIVERY_MODE=feishu_appFEISHU_APP_IDFEISHU_APP_SECRETFEISHU_CHAT_ID)→ setup-approle → deploy_v2 → alerting.test-feishu

SOP-004 / SOP-004B / SOP-004C: 应用 OTEL 错误告警 + finance_report 告警目录 config-as-code(#373 / #1106)

  1. bridge 健康 + SigNoz API key + Feishu channel(SOP-002/004 步骤)。
  2. 应用定义(幂等):
    uv run python -m invoke fr-observability.shared.apply-alerts
    uv run python -m invoke fr-observability.shared.apply-dashboard
    uv run python -m invoke fr-observability.shared.print-alerts   # 离线看 payload
    
  3. #1106 SLO/business 目录:FinanceReportHigh5xxRate(5xx>5% 5m,P0)、FinanceReportP95LatencyHigh(p95>1500ms,P1)、FinanceReportStatementParseFailureSpikeFinanceReportReconciliationAnomalyFinanceReportRateLimitSaturation(P2)、FinanceReportAsyncTaskFailures。须渲染为 SigNoz v5 PromQL(alertType=METRIC_BASED_ALERT, ruleType=promql_rule, condition.compositeQuery.queries[]);SigNoz 拒任一规则即 fail 整个 apply(部分 apply 不算成功 GitOps)。
  4. 先跑 schema canary:gh workflow run apply-observability.yml --ref <ref> -f mode=canary(建一条 disabled PromQL 规则验 v5 信封再删)。apply 应在 app 发完所有引用 metric 名后。

:apply_alerts 现为声明式 reconcile(upsert + 默认只 log 的 prune),见 ops.pipeline.md

SOP-005: Cloudflare 带外 watchdog(主,边缘 30min)

活在 cloudflare/infra-watchdog,直发 Feishu(不经它要验证的 bridge)。归属按信号记于 watchdog-signals.yaml。默认覆盖:prod 公网路由 cloud/vault/minio/sso/signoz + report web/api;staging 选定路由;prod/staging probe-runner heartbeat 新鲜度。每个 target 携带 registry 校验的 service_id;结构化事件写 identity_schema=v1 / managed_by=infra2,dedupe keys on stable failure identity plus failure domain,具体 fingerprint 使用 (environment, service_id, signal, failure_domain)。config-preflight 失败单独报(不冒充路由故障);投递失败发 watchdog.delivery.failure 结构化事件不静默。 - secrets:webhook 模式 FEISHU_WEBHOOK_URL;app 模式 FEISHU_APP_SECRET;两者 HEARTBEAT_TOKENWATCHDOG_STATUS_TOKEN(源 1Password Infra2/bootstrap/cloudflare-worker)。 - KV WATCHDOG_STATE;vars WATCHDOG_ENVIRONMENTS=production,stagingWATCHDOG_RENOTIFY_SECONDS=7200 等。 - 部署:cd cloudflare/infra-watchdog && wrangler kv namespace create WATCHDOG_STATE && wrangler secret put ... && wrangler deploy;再配 probe runner heartbeat:env.set INFRA_PROBE_HEARTBEAT_URL=.../heartbeat + INFRA_PROBE_HEARTBEAT_TOKEN(prod+staging)→ deploy_v2。

SOP-005B: GitHub 兜底带外 watchdog(日级)

活在 GitHub Actions(在 infra2 宿主之外),日级直发 Feishu;留作 SSH 宿主诊断、Cloudflare Worker 自检、Dokploy 控制面状态消费、手动诊断。secrets:INFRA2_WATCHDOG_SSH_{HOST,USER,PRIVATE_KEY}INFRA2_WATCHDOG_WORKER_STATUS_TOKENDOKPLOY_API_KEY + Feishu 投递 secrets。默认查:公网 Dokploy 入口、Worker /health+/status、SSH 可达、Docker daemon、platform-alerting 容器内 /healthinfra2-docker-health 检查强制(任何 unhealthy/starting/Restarting 容器在部署窗口外即失败),不可移除。投递异常时发 watchdog.delivery.failure + 开 GitHub fallback issue(label watchdog-alert-fallback)+ 非零退出。

已知外部极限:若 watchdog 与 Feishu/Lark 用的所有外部通道同时不可用,本仓库没有第三条独立人工通知通道(#425 月级/兜底范畴)。

SOP-006: In-band 服务探针(分钟级)

INFRA_PROBE_SPECS 由各服务 deploy.py Deployer 的 ProbeFacet 声明渲染(#541 单一声明点:聚合器 libs/probe_specs.py::render_probe_spec_text()AlertingDeployer.compose_env_base() 注入 Dokploy env;迁移前的手写 literal 冻结为 libs/tests/fixtures/infra_probe_specs_frozen.txt,由 libs/tests/test_probe_specs_equivalence.py 做永久逐字段等价回归)。循环 INFRA_PROBE_INTERVAL_SECONDS=60(快检);通知分离:FAILURE_THRESHOLD=3RECOVERY_THRESHOLD=2RENOTIFY_SECONDS=1800。优先 Docker 网络目标(公网路由归 Cloudflare watchdog;error code: 1010 归类 probe-client-blocked)。spec 格式 name|kind|target|expected|severity|timeout|depends_on|service_id;kind=http/tcp/command。第八字段强制绑定 registry。depends_on 链命中失败 root → 级联抑制(环路 fail-closed,见 tools/infra_probe_runner.py)。dry-run:INFRA_PROBE_DRY_RUN=1 uv run python tools/infra_probe_runner.py --once --json

公网路由探针(#543,反转 #209):PUBLIC_ROUTE_PROBE_SPECS 由各服务的 PublicRouteFacet 声明渲染(libs/probe_specs.py::render_public_route_spec_text,域名渲染期解析、无 $ 传输);prod_only 服务只渲染生产、非生产一律降为 warning。每个渲染出的 *-public-route 名字必须是已注册 signal(libs/tests/test_infra_probes.py 锁定)。

内部 signal 注册派生(#543):watchdog-signals.yamlprimary_owner: internal 条目不再手写,由 libs/watchdog_signal_entries.py 从 ProbeFacet+SignalFacet 派生(声明探针即注册 signal);watchdog_consistency_audit.py 加载时合并派生条目、拒绝手写 internal 条目,并对派生条目强制 #425 T5 tier/type/debounce 校验;跨平面条目(cloudflare/github/self/excluded)仍手写。手写时代的 39 条冻结于 libs/tests/fixtures/watchdog_internal_signals_frozen.yaml,libs/tests/test_watchdog_signal_entries.py 做永久逐字段等价回归。

常驻拓扑(#543 单 sidecar):probe-runner(platform-alerting-probes)是仓库唯一常驻进程;container-breakdown watch 与 deploy-queue guard 以 ResidentWatcher 插件(libs/resident_watchers.py)在其循环内自节奏运行,故障隔离、由 runner 的 healthcheck/heartbeat 兜底(挂起 watcher → state file 过期 → compose healthcheck 重启)。新增常驻能力 = 新增 watcher 插件,不新建 sidecar。

alert-delivery-canary 已退役(#425 T3):它把"投递自证"做成了 6h 周期性告警(报告当告警),是 #425 禁止的反模式。bridge→Feishu 路径现由 lark-delivery-http + 带外 watchdog 的 bridge /health + 日报投递 + 真实告警覆盖,告警频道不再被合成事件刷屏。

SOP-007: Dokploy route canary(已退役,#543)

已退役:每小时部署合成 compose 的 route canary(tools/dokploy_route_canary.py + libs/dokploy_route_canary.py,约 1000 行)整体删除,不设观察期。其原有覆盖由更便宜的常驻机制承接:公网路由可达性 → PublicRouteFacet 声明渲染进 probe runner(SOP-006)+ Cloudflare watchdog;Dokploy 控制面/部署状态 → 带外 watchdog 的 run_dokploy_status_check(缺 DOKPLOY_API_KEY fail-closed 归类 configuration,签名由 canary 移交);部署卡死 → deploy-queue guard(常驻 sidecar 插件)。真实 preview 路由回归由 app PR preview 流程自身承担。

SOP-007B: deploy_v2 Canary(日级/变更触发)

tools/deploy_v2_canary.py 只使用保留的 pr-999 预览位,健康检查后必须清理 stack 与临时 DB。 成功保持静默,仅在 GitHub summary 输出 infra2-sdk v1.0.0 StageResult;非 PR 失败才经带外 Feishu page,且告警携带同一结构化记录。不得通过破坏 production 数据或恢复周期性 alert-delivery-canary 来制造失败;Feishu 正向投递仍由日报送达自证。

SOP-008: 账本冷归档 + 周报

  • R2:确认桶 infra2 + wrangler.toml [[r2_buckets]] binding=LEDGER_BUCKETwrangler deploy;跨天后 R2 watchdog-ledger/ 出现昨日 JSON。
  • 周报:ops-checks.yml(周一 UTC)跑 stability_report.py/ledger → Lark;本地 INFRA2_STABILITY_REPORT_DRY_RUN=1 python tools/stability_report.py --input ledger.json

8. 部署与容量

部署顺序:存储(clickhouse)→ 应用(signoz)→ 告警(alerting),各 deploy_v2 --service ... --type prod --iac-ref vX.Y.Z --code-reviewed,invoke {clickhouse,signoz,alerting}.status 验证。容量:ClickHouse 磁盘 100GB+ / 内存 8GB+ / Collector 1GB(memory_limiter)。alert bridge 启动等 /secrets/.env 最多 300s,但不得要求 vault-agent sidecar 在渲染后保持 Docker-healthy(stale-secret 是另一条服务级信号,不阻塞告警投递)。


9. 验证与测试 (The Proof)

行为 测试锚点 状态
采集:ClickHouse/SigNoz/bridge 健康 + OTLP 可用 invoke {clickhouse,signoz,alerting}.statussignoz.shared.test-trace
Feishu payload + 日志错误规则 payload libs/tests/test_alerting.py
finance_report 告警/看板 config-as-code(#373) libs/tests/test_observability_dashboards.py
Cloudflare / out-of-band / GitHub 兜底 watchdog 契约 test_cloudflare_watchdog.py, test_out_of_band_watchdog.py
In-band 服务探针 + 级联抑制 libs/tests/test_infra_probes.py
Deploy-queue guard(卡死检测纯逻辑 + sidecar 编排:env 加载、扫描失败隔离、renotify 抑制、remediate/升级序列) libs/tests/test_deploy_queue.py, libs/tests/test_deploy_queue_guard.py
备份新鲜度告警 payload libs/tests/test_backup_verification.py
账本聚合(正例+反例:降级绝不报 100%/perfect、畸形输入不抬高、0 检查不除零) libs/tests/test_availability_ledger.py
Worker 账本 + /ledger + R2 归档 libs/tests/test_cloudflare_watchdog.py
周 watchdog recall digest / 周正向稳定性报告 test_watchdog_weekly_digest.py, test_stability_report.py
Env×Stage failure-domain / disagreement 契约 libs/tests/test_pipeline_stage_contract.py
synthetic round-trip test_observability_roundtrip_probe.py
IaC/runtime/telemetry/alert 身份契约 tools/service_identity_audit.py, libs/tests/test_service_identity*.py
告警通道手动连通 uv run invoke alerting.test-feishu Manual gate

10. 故障排查

  • ClickHouse 启动失败:docker logs platform-clickhouse${ENV_SUFFIX};常见权限(uid=101)/磁盘 → invoke clickhouse.pre-compose
  • OTLP 未显示:docker logs platform-signoz-otel-collector;查 otel-collector-config.yaml exporter。
  • Frontend 502:docker logs platform-signoz${ENV_SUFFIX};等 query-service 健康。

Used by