Правки от GPT
This commit is contained in:
@@ -0,0 +1,572 @@
|
||||
# module-09. Наблюдаемость production-like контура
|
||||
|
||||
> Статус: целевая спецификация наблюдаемости MVP на одной VM.
|
||||
> Источники: [`README.md`](README.md), [`arch-00-glossary.md`](arch-00-glossary.md), [`arch-01-system-architecture.md`](arch-01-system-architecture.md), [`arch-02-api-contracts.md`](arch-02-api-contracts.md), [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md), [`arch-04-settings-and-content.md`](arch-04-settings-and-content.md), [`arch-05-agent-development-process.md`](arch-05-agent-development-process.md), [`module-01-api-backend.md`](module-01-api-backend.md)–[`module-08-keycloak.md`](module-08-keycloak.md).
|
||||
|
||||
## 1. Цели и границы
|
||||
|
||||
Наблюдаемость должна позволять:
|
||||
|
||||
- найти пользовательский запрос по `request_id`, `trace_id` или `ux_session_id`;
|
||||
- восстановить путь «frontend → nginx → API → Safety → S3/Open Lines»;
|
||||
- измерять доступность, задержку, ошибки и насыщение каждого сервиса;
|
||||
- обнаруживать backlog, DLQ, circuit open, потерю telemetry и истечение TLS;
|
||||
- расследовать security/audit события без записи PII и секретов;
|
||||
- проверять SLO по данным, независимым от бизнес-логов.
|
||||
|
||||
Telemetry не является источником бизнес-истины и не влияет на auth, safety verdict или доставку сообщений. Недоступность Collector не должна блокировать запросы. Audit в `han_app` — отдельный durable контур.
|
||||
|
||||
## 2. Production-like решение MVP
|
||||
|
||||
### 2.1. Обязательный минимум в основном Compose
|
||||
|
||||
Архитектура явно требует только `otel-collector`. Поэтому **основной production-like Compose обязан содержать Collector, но не обязан размещать Prometheus/Grafana/Loki/Tempo на той же VM**.
|
||||
|
||||
Предпочтительный operable-вариант после выбора backend:
|
||||
|
||||
1. приложения экспортируют OTLP gRPC в `otel-collector:4317`;
|
||||
2. Collector отправляет telemetry в выбранный удалённый управляемый OTLP backend провайдера;
|
||||
3. JSON stdout остаётся аварийным локальным журналом Docker с rotation;
|
||||
4. пока удалённый backend не выбран, допустим архитектурный минимум из arch-03: bounded JSON stdout/platform logs и Collector `debug` exporter с sampling в acceptance; такой режим не считается полноценным production-хранением и не закрывает alerting/SLO.
|
||||
|
||||
Требуемые возможности удалённого backend: OTLP ingest, поиск traces, PromQL-совместимые или эквивалентные metrics, поиск структурированных logs, alerting, RBAC, retention и TLS.
|
||||
|
||||
### 2.2. Самостоятельно размещаемая опция
|
||||
|
||||
Опциональный Compose profile `observability-local` может включать:
|
||||
|
||||
- Prometheus — scrape метрик Collector/Redis/Keycloak/nginx exporters;
|
||||
- Grafana — dashboards и alerts;
|
||||
- Loki — логи;
|
||||
- Tempo — traces.
|
||||
|
||||
Он **не включается по умолчанию на малой VM**: стек требует дополнительной RAM/диска и сам становится объектом backup/monitoring. Для operable local-варианта нужны отдельный volume каждому backend, retention limits, compaction, auth через ops/VPN и отсутствие host ports. Grafana доступна только через отдельный защищённый ops route/VPN, не через публичный `/`.
|
||||
|
||||
Рекомендуемый минимум VM при local profile: дополнительно 4 vCPU, 8 ГБ RAM и 100+ ГБ SSD сверх приложения; точный размер — после измерения ingest.
|
||||
|
||||
## 3. Архитектура Collector
|
||||
|
||||
### 3.1. Компоненты
|
||||
|
||||
```text
|
||||
backend services ─OTLP gRPC/HTTP─┐
|
||||
nginx/Redis/Keycloak exporters ──┼─> otel-collector
|
||||
Docker JSON stdout ─filelog───────┘ ├─ OTLP/TLS remote backend
|
||||
├─ Prometheus endpoint (optional)
|
||||
└─ debug exporter (acceptance only)
|
||||
```
|
||||
|
||||
Collector запускается одним сервисом MVP. При росте разделяется на agent/gateway: локальный agent принимает и буферизует, remote gateway выполняет policy/export.
|
||||
|
||||
### 3.2. Receivers
|
||||
|
||||
- `otlp` gRPC `0.0.0.0:4317` — основной internal receiver;
|
||||
- `otlp` HTTP `0.0.0.0:4318` — совместимость SDK;
|
||||
- `prometheus` — scrape самого Collector, Keycloak metrics, Redis exporter, nginx exporter и сервисных `/metrics`, если они не идут OTLP;
|
||||
- `filelog` — только если Docker logging driver предоставляет read-only каталог/volume; парсит JSON stdout без чтения secret-файлов;
|
||||
- `hostmetrics` — CPU, memory, filesystem, network VM/container host, если Collector получает только необходимые read-only mounts.
|
||||
|
||||
Порты `4317`, `4318`, `8888`, `8889` используют `expose`, не `ports`. Receiver доступен только в сети `observability`.
|
||||
|
||||
### 3.3. Processors и порядок
|
||||
|
||||
Во всех pipelines первым стоит защита памяти, последним — batch:
|
||||
|
||||
1. `memory_limiter`: check interval 1s, soft/hard limit относительно container memory;
|
||||
2. `resource`: нормализует `service.namespace=han-chat`, `deployment.environment`, `service.version`;
|
||||
3. `attributes`: удаляет/маскирует sensitive attributes;
|
||||
4. `transform`: нормализует route/status/error semantic conventions;
|
||||
5. `filter`: исключает health noise, debug events и запрещённые поля;
|
||||
6. `probabilistic_sampler` или tail sampling для traces;
|
||||
7. `batch`: bounded batch/timeout;
|
||||
8. при remote export — `queued_retry`/sending queue и `file_storage` extension.
|
||||
|
||||
`memory_limiter` не заменяется Docker OOM limit. При pressure Collector отбрасывает telemetry контролируемо и увеличивает `otelcol_processor_refused_*`.
|
||||
|
||||
### 3.4. Exporters
|
||||
|
||||
- `otlp/remote`: TLS verify, endpoint и auth header из secret env/mount;
|
||||
- `prometheus`: optional pull endpoint только internal;
|
||||
- `debug`: только `APP_ENV=test|acceptance`, verbosity normal; production debug exporter по умолчанию выключен;
|
||||
- `loki`/`otlphttp` — только если выбран backend и его контракт закреплён.
|
||||
|
||||
Секрет exporter-а не должен появляться в rendered config, логах или `/debug/configz`. Config монтируется read-only; secret подставляется env.
|
||||
|
||||
### 3.5. Extensions
|
||||
|
||||
- `health_check` — internal endpoint, используется Compose;
|
||||
- `pprof`/`zpages` — только при явном ops profile, internal network;
|
||||
- `file_storage` — persistent sending queue на volume `otel-queue`;
|
||||
- `basicauth`/`oauth2client` — если требует remote backend.
|
||||
|
||||
### 3.6. Принципиальная конфигурация
|
||||
|
||||
```yaml
|
||||
receivers:
|
||||
otlp:
|
||||
protocols:
|
||||
grpc: {endpoint: 0.0.0.0:4317}
|
||||
http: {endpoint: 0.0.0.0:4318}
|
||||
prometheus:
|
||||
config:
|
||||
scrape_configs:
|
||||
- job_name: otel-collector
|
||||
static_configs: [{targets: ["127.0.0.1:8888"]}]
|
||||
|
||||
processors:
|
||||
memory_limiter:
|
||||
check_interval: 1s
|
||||
limit_mib: 384
|
||||
spike_limit_mib: 96
|
||||
resource/common:
|
||||
attributes:
|
||||
- {key: service.namespace, value: han-chat, action: upsert}
|
||||
- {key: deployment.environment, value: "${env:APP_ENV}", action: upsert}
|
||||
attributes/redact:
|
||||
actions:
|
||||
- {key: http.request.header.authorization, action: delete}
|
||||
- {key: http.request.header.cookie, action: delete}
|
||||
- {key: url.query, action: delete}
|
||||
- {key: db.statement, action: delete}
|
||||
filter/noise:
|
||||
error_mode: ignore
|
||||
traces:
|
||||
span:
|
||||
- 'attributes["http.route"] == "/health/live"'
|
||||
batch:
|
||||
send_batch_size: 1024
|
||||
timeout: 5s
|
||||
|
||||
exporters:
|
||||
otlp/remote:
|
||||
endpoint: "${env:OTEL_REMOTE_ENDPOINT}"
|
||||
tls: {insecure: false}
|
||||
headers: {authorization: "${env:OTEL_REMOTE_AUTH_HEADER}"}
|
||||
|
||||
extensions:
|
||||
health_check: {endpoint: 0.0.0.0:13133}
|
||||
file_storage: {directory: /var/lib/otelcol/queue}
|
||||
|
||||
service:
|
||||
extensions: [health_check, file_storage]
|
||||
pipelines:
|
||||
traces:
|
||||
receivers: [otlp]
|
||||
processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch]
|
||||
exporters: [otlp/remote]
|
||||
metrics:
|
||||
receivers: [otlp, prometheus]
|
||||
processors: [memory_limiter, resource/common, attributes/redact, batch]
|
||||
exporters: [otlp/remote]
|
||||
logs:
|
||||
receivers: [otlp]
|
||||
processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch]
|
||||
exporters: [otlp/remote]
|
||||
telemetry:
|
||||
metrics: {address: 0.0.0.0:8888}
|
||||
```
|
||||
|
||||
Конкретная версия schema проверяется командой Collector `validate`; image закрепляется по digest. Значения memory/batch/queue — стартовые, не SLO.
|
||||
|
||||
## 4. Resource attributes и корреляция
|
||||
|
||||
Обязательные resource attributes:
|
||||
|
||||
- `service.name`: `nginx`, `api-backend`, `message-safety`, `bitrix-local-app`, `bitrix-sync`, `keycloak`, `redis`, `otel-collector`;
|
||||
- `service.namespace=han-chat`;
|
||||
- `service.version=<release-or-git-sha>`;
|
||||
- `deployment.environment=production-like|production`;
|
||||
- `host.name`/`service.instance.id` без публичного IP.
|
||||
|
||||
Обязательные поля request-события:
|
||||
|
||||
- `request_id`;
|
||||
- `trace_id`, `span_id`;
|
||||
- `ux_session_id` — nullable, только когда передан;
|
||||
- `service.name`;
|
||||
- `environment` либо canonical `deployment.environment`.
|
||||
|
||||
`request_id` формирует/валидирует nginx; сервис возвращает его клиенту и передаёт downstream. `trace_id` берётся из active span. `ux_session_id` не является auth и не должен использоваться как metric label.
|
||||
|
||||
## 5. W3C propagation
|
||||
|
||||
- принимаются только валидные `traceparent` и опциональный `tracestate`;
|
||||
- nginx передаёт context в API; при edge instrumentation создаёт server span;
|
||||
- API создаёт child spans для PostgreSQL, Redis, S3, Safety, Open Lines и JWKS;
|
||||
- internal calls передают `traceparent`, `tracestate`, `X-Request-ID`;
|
||||
- `baggage` по умолчанию не принимается от внешнего клиента; если включён, allow-list исключает PII;
|
||||
- Bitrix24/S3 могут не вернуть context: внешний client span всё равно закрывается результатом;
|
||||
- async outbox/inbox связывается span link с исходным trace; новый worker trace не притворяется продолжением спустя долгий срок.
|
||||
|
||||
Frontend может отправлять валидный `traceparent`, но backend не доверяет его sampling/security атрибутам.
|
||||
|
||||
## 6. JSON stdout contract
|
||||
|
||||
Одна JSON-запись на строку UTF-8:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-07-10T09:00:00.123Z",
|
||||
"level": "INFO",
|
||||
"service.name": "api-backend",
|
||||
"service.version": "git-abcdef0",
|
||||
"environment": "production-like",
|
||||
"module": "message_service",
|
||||
"event": "message.delivery.completed",
|
||||
"message": "Message delivery completed",
|
||||
"request_id": "01J...",
|
||||
"trace_id": "32hex",
|
||||
"span_id": "16hex",
|
||||
"ux_session_id": "uuid-or-null",
|
||||
"route": "/api/v1/dialogs/{dialog_id}/messages",
|
||||
"method": "POST",
|
||||
"status_code": 201,
|
||||
"duration_ms": 742,
|
||||
"dependency": "bitrix-local-app",
|
||||
"outcome": "success",
|
||||
"error_code": null
|
||||
}
|
||||
```
|
||||
|
||||
Правила:
|
||||
|
||||
- `event` — стабильная mnemonic, `message` — безопасное описание;
|
||||
- route — template, никогда raw URI с id/query;
|
||||
- stack trace допускается только в internal error log после redaction;
|
||||
- message text, callback body, SQL values и file content запрещены;
|
||||
- Docker driver ограничен `50m × 5`, но это buffer, не retention backend;
|
||||
- multiline stack trace сериализуется полем JSON, не отдельными строками.
|
||||
|
||||
## 7. Redaction и data minimization
|
||||
|
||||
Удаляются или маскируются:
|
||||
|
||||
- `Authorization`, Cookie, Set-Cookie, JWT, OAuth/code/refresh/access tokens;
|
||||
- raw OTP/mock code, Keycloak admin/client password;
|
||||
- phone/email/full name, device id, IP по policy (допустим HMAC/truncated);
|
||||
- message text, filenames с PII, document/file contents;
|
||||
- DSN/password, Redis URL, S3 keys;
|
||||
- presigned URL и любая query string;
|
||||
- Bitrix raw payload/download URL/application token;
|
||||
- `db.statement` с literals; предпочтительно operation/table, не SQL.
|
||||
|
||||
Redaction выполняется в SDK/logger **до stdout**, затем повторяется Collector processor. Collector не может считаться единственной защитой. Автотесты отправляют canary secrets/PII и требуют отсутствие во всех трёх сигналах.
|
||||
|
||||
## 8. Instrumentation по компонентам
|
||||
|
||||
### 8.1. FastAPI-сервисы
|
||||
|
||||
- OpenTelemetry ASGI/FastAPI server spans с route template;
|
||||
- HTTPX client spans с sanitized host/method/status;
|
||||
- SQLAlchemy/asyncpg spans без параметров и raw statement;
|
||||
- Redis instrumentation с command name и DB index, без key/value;
|
||||
- boto/S3 spans: operation/bucket logical name, без object key/query;
|
||||
- background workers: span на claim/process/finalize, links на origin;
|
||||
- исключить `/health/live` из traces; readiness оставить в metrics и sampled logs.
|
||||
|
||||
### 8.2. PostgreSQL
|
||||
|
||||
Собираются pool wait/checked-out, transaction duration, error class, migrations revision, managed PG provider metrics (CPU, storage, connections, locks, replication/PITR state). `user_id`, SQL text и row data не labels.
|
||||
|
||||
### 8.3. Redis
|
||||
|
||||
`redis_exporter` подключается отдельным ACL user только на `INFO`, `PING`, безопасные latency/keyspace metrics. Нужны memory ratio, evictions, expirations, blocked/rejected clients, command latency, AOF status/rewrite, Pub/Sub buffers, key count/TTL агрегаты. Keys/values не экспортируются.
|
||||
|
||||
### 8.4. Keycloak
|
||||
|
||||
Включаются management metrics/JVM/HTTP/DB pool. Custom OTP provider публикует counters send/verify/limit/settings-cache без phone labels. Login events идут в JSON/audit с masked/HMAC destination. Public OIDC synthetic проверяется отдельно.
|
||||
|
||||
### 8.5. nginx
|
||||
|
||||
JSON access log содержит `request_id`, извлечённый `trace_id`, route class, method, normalized path, status, bytes, request/upstream duration/status, TLS version, cache status. `$request` с query не используется.
|
||||
|
||||
Collector `filelog` parser:
|
||||
|
||||
- разбирает JSON, timestamp и severity;
|
||||
- переносит `service.name=nginx`;
|
||||
- превращает пустые/`-` в null;
|
||||
- route class нормализует в bounded set;
|
||||
- отбрасывает ACME/health success noise;
|
||||
- не парсит raw URI в labels.
|
||||
|
||||
Native nginx OTEL module предпочтителен, если image/version закреплены. Без него nginx только передаёт W3C context и коррелирует access log; первый server span создаёт API.
|
||||
|
||||
### 8.6. Host/Docker
|
||||
|
||||
CPU, load, memory/swap, disk usage/inodes/IO, network, container restarts/OOM, Docker daemon health и clock sync. Container name/version — bounded labels; container id не хранится как долгосрочный high-cardinality label.
|
||||
|
||||
## 9. Метрики бизнес-потоков
|
||||
|
||||
### API и auth
|
||||
|
||||
- `han_http_requests_total{service,route,method,status_class}`;
|
||||
- `han_http_request_duration_seconds`;
|
||||
- `han_auth_bootstrap_total{outcome}`;
|
||||
- `han_ux_session_start_total{reason}`;
|
||||
- `han_jwks_refresh_total{outcome}`;
|
||||
- `han_rate_limit_decisions_total{scope,outcome}`.
|
||||
|
||||
### Message Safety
|
||||
|
||||
- checks/verdicts по `allow|deny|pending|error`;
|
||||
- poll duration/count buckets, timeout и recovery backlog age;
|
||||
- stub mode info и terminal `400` отдельно, пока действует test-only контракт;
|
||||
- cache hit, Redis latency, task expired/not-found.
|
||||
|
||||
### Open Lines/Bitrix
|
||||
|
||||
- message submitted → delivered end-to-end latency;
|
||||
- local app outbound result/retry/ambiguous/DLQ;
|
||||
- inbox depth/oldest age/forward retries/duplicate;
|
||||
- OAuth time-to-expiry/refresh result;
|
||||
- connector desired/observed state;
|
||||
- Bitrix 429, circuit state, setup failure.
|
||||
|
||||
### Files/S3
|
||||
|
||||
- init/complete/promote/delete;
|
||||
- quarantine object age/orphans;
|
||||
- checksum/MIME/size reject;
|
||||
- presigned download issued;
|
||||
- S3 dependency latency/error by operation and logical bucket.
|
||||
|
||||
### Frontend synthetic
|
||||
|
||||
- public config/content;
|
||||
- OIDC discovery/authorization page;
|
||||
- WS handshake;
|
||||
- test-user end-to-end flow в отдельной тестовой identity без реального PII.
|
||||
|
||||
Никакие UUID/user/session/dialog/task/message id не labels. Они допустимы только в sampled logs/traces при принятой retention.
|
||||
|
||||
## 10. Dashboards
|
||||
|
||||
1. **Executive/SLO**: availability, error budget burn, p50/p95/p99, message delivery, auth, active incidents.
|
||||
2. **nginx edge**: RPS, 4xx/5xx, upstream latency/status, 429, WS, TLS, cache.
|
||||
3. **api-backend**: routes, DB/Redis pools, JWKS, circuits, outbox/safety backlog, S3.
|
||||
4. **message-safety**: verdicts, pending/poll, task TTL, Redis, distribution stub outcomes.
|
||||
5. **bitrix-local-app**: install/OAuth, connector, outbound/inbox/DLQ, API/Bitrix latency.
|
||||
6. **bitrix-sync**: mode, DB probe, last success/staleness; нельзя показывать CRM sync как рабочий в stub.
|
||||
7. **Keycloak**: login/OTP/lockout, sessions/tokens, provider settings cache, JVM/DB.
|
||||
8. **Redis**: memory/evictions/AOF/latency/clients/keyspace.
|
||||
9. **PostgreSQL/S3**: provider metrics, storage, connections, backup/PITR, object errors.
|
||||
10. **Business flow**: guest config → OTP → bootstrap → session → dialog → safety → Open Lines → operator reply.
|
||||
11. **Collector health**: accepted/sent/refused/dropped, queue, retry, exporter errors, memory/CPU.
|
||||
|
||||
Каждая панель содержит release annotation, environment filter и links trace→logs по `trace_id`.
|
||||
|
||||
## 11. SLI, SLO и alerts
|
||||
|
||||
Значения — начальная production-like политика до load/product review:
|
||||
|
||||
| SLI | Initial SLO, 30 дней |
|
||||
|---|---|
|
||||
| HTTPS edge availability | 99.9% |
|
||||
| public config/content successful requests | 99.9% |
|
||||
| protected read API successful requests | 99.5% |
|
||||
| Keycloak login flow availability | 99.5% |
|
||||
| text message accepted и доставлен в Open Lines | 99.0% |
|
||||
| operator inbox applied без permanent loss | 99.5% |
|
||||
| p95 protected read API | < 750 ms |
|
||||
| p95 text send без внешнего rate limit | < 5 s |
|
||||
| telemetry Collector ingest availability | 99.0%, не входит в business availability |
|
||||
|
||||
Файловый send измеряется отдельно: p95 не должен превышать configured safety poll budget; user-cancel, safety deny, 4xx validation и edge abuse 429 не считаются server failure. 503/504 и unexpected 5xx считаются.
|
||||
|
||||
### Paging alerts
|
||||
|
||||
- multi-window burn: 14.4× за 5m/1h или 6× за 30m/6h;
|
||||
- edge/API 5xx >5% 5 минут;
|
||||
- text delivery failure >5% 10 минут;
|
||||
- oldest outbox/inbox/safety task >5 минут либо DLQ >0;
|
||||
- Keycloak login failures infrastructure class >10% 5 минут;
|
||||
- PostgreSQL unavailable/connection saturation >90%;
|
||||
- Redis unavailable, AOF error или sustained evictions;
|
||||
- Collector exporter queue >80%, dropped/refused telemetry >0 sustained;
|
||||
- TLS expiry <14 дней warning, <7 дней page;
|
||||
- disk >85% warning, >92% page; OOM/restart loop;
|
||||
- managed PG backup/PITR failure.
|
||||
|
||||
### Ticket/warning alerts
|
||||
|
||||
- p95 regression 20% release-over-release;
|
||||
- settings/JWKS cache stale;
|
||||
- bitrix-sync stub probe stale >150s;
|
||||
- OAuth expires <24h без успешного refresh;
|
||||
- quarantine orphan growth;
|
||||
- cardinality/ingest growth >2× baseline.
|
||||
|
||||
Alert содержит service, environment, symptom, dashboard, runbook, release и безопасный query; не содержит PII.
|
||||
|
||||
## 12. Sampling, cardinality и retention
|
||||
|
||||
### Traces
|
||||
|
||||
- errors/5xx, circuit, timeout, DLQ, safety final deny и slow requests — 100%;
|
||||
- обычные успешные requests — 5–10%;
|
||||
- health/ACME success — 0%;
|
||||
- tail sampling предпочтителен в Collector, но head sample SDK должен оставлять достаточно данных;
|
||||
- sampling decision передаётся W3C.
|
||||
|
||||
### Metrics
|
||||
|
||||
Allow-list labels; route template вместо raw path; status class/known code; dependency enum. Cardinality budget: целевой <10 000 active series на MVP environment. CI проверяет запрещённые labels.
|
||||
|
||||
### Retention initial
|
||||
|
||||
- metrics: 30 дней high resolution, 13 месяцев downsampled при доступности backend;
|
||||
- traces: 7 дней, errors 14 дней;
|
||||
- technical logs: 14 дней, security/auth logs 30 дней;
|
||||
- audit `han_app`: 365 дней **только как временное допущение до legal policy**;
|
||||
- raw Bitrix callback не хранится в telemetry;
|
||||
- local Docker logs: не более 250 МБ/container и 5 файлов.
|
||||
|
||||
Legal retention/erasure имеет приоритет; изменение требует обновления policy и backup lifecycle.
|
||||
|
||||
## 13. Collector health и отказоустойчивость
|
||||
|
||||
Контролируются:
|
||||
|
||||
- `/health` extension;
|
||||
- process CPU/RSS/restarts;
|
||||
- accepted/refused/sent/failed spans, points, records;
|
||||
- batch send size/latency;
|
||||
- exporter queue capacity/size, enqueue failures, retry age;
|
||||
- file storage usage/corruption;
|
||||
- scrape failures;
|
||||
- config reload/validation.
|
||||
|
||||
При remote outage queue хранится на `otel-queue` с bounded size/age. При заполнении отбрасываются сначала low-priority success traces/logs; приложение продолжает работу. Нельзя позволять queue заполнить системный диск.
|
||||
|
||||
## 14. Docker Compose
|
||||
|
||||
`otel-collector`:
|
||||
|
||||
- pinned contrib image;
|
||||
- networks: только `observability`, а для scrape internal targets — минимально необходимая `backend`;
|
||||
- `expose`: 4317, 4318, 13133, 8888/8889;
|
||||
- без host ports;
|
||||
- config read-only, `otel-queue` volume rw;
|
||||
- non-root, read-only rootfs, tmpfs `/tmp`, drop capabilities, no-new-privileges;
|
||||
- initial limit: 0.5 CPU/512 MiB, queue disk 5–10 ГБ; уточнить load test;
|
||||
- healthcheck extension;
|
||||
- restart policy с backoff;
|
||||
- приложения имеют bounded non-blocking OTLP exporter queue.
|
||||
|
||||
Доступ к Docker socket запрещён. Для container metrics используется безопасный exporter/hostmetrics, а не unrestricted socket mount.
|
||||
|
||||
## 15. Security
|
||||
|
||||
- OTLP receiver internal-only; при переходе между hosts — mTLS;
|
||||
- remote exporter только TLS verify, credentials least privilege;
|
||||
- Grafana/Prometheus/Loki/Tempo не публичны;
|
||||
- RBAC: viewer/operator/admin; audit доступа к logs/traces;
|
||||
- dashboards не показывают PII;
|
||||
- config/secret permissions 0400/0600;
|
||||
- dependency/image scan и SBOM;
|
||||
- защита от log injection: JSON encoding, control chars, bounded field lengths;
|
||||
- telemetry input не исполняет expressions из пользовательских значений;
|
||||
- регулярная secret-canary проверка и incident deletion procedure.
|
||||
|
||||
## 16. Runbooks
|
||||
|
||||
### Collector not-ready
|
||||
|
||||
1. `docker compose ps otel-collector` и bounded logs.
|
||||
2. Проверить config validation, memory/OOM, queue volume.
|
||||
3. Проверить DNS/TLS/auth remote exporter.
|
||||
4. Не рестартовать бесконечно при полной queue; сначала освободить/расширить безопасно.
|
||||
5. Бизнес-сервисы оставить работающими; подтвердить local JSON logs.
|
||||
6. После восстановления проверить drain и gap.
|
||||
|
||||
### Telemetry отсутствует у одного сервиса
|
||||
|
||||
1. Проверить `service.name`, endpoint/protocol и сеть `observability`.
|
||||
2. Проверить SDK queue/drop counters и clock.
|
||||
3. Отправить synthetic request с `X-Request-ID`.
|
||||
4. Найти его в stdout, Collector accepted и backend.
|
||||
5. Проверить sampling/filter/redaction rules.
|
||||
|
||||
### Remote backend outage
|
||||
|
||||
1. Подтвердить exporter errors, а не application outage.
|
||||
2. Оценить queue fill rate/time-to-full.
|
||||
3. Ограничить debug exporter; не включать verbose.
|
||||
4. При длительном outage увеличить sampling только через reviewed config.
|
||||
5. После восстановления подтвердить drain и создать incident note о потере данных.
|
||||
|
||||
### Cardinality/ingest spike
|
||||
|
||||
1. Найти новое metric/log attribute по release annotation.
|
||||
2. Отключить offending instrument/filter в Collector.
|
||||
3. Проверить raw path/id/user/session labels.
|
||||
4. Rollback instrumentation при риске стоимости/доступности.
|
||||
5. Добавить CI regression test.
|
||||
|
||||
### Высокая latency сообщения
|
||||
|
||||
1. Открыть trace по request id.
|
||||
2. Разделить API, Safety poll, S3, local app, Bitrix.
|
||||
3. Проверить circuit, queue age, DB pool и Redis.
|
||||
4. Не повторять ambiguous message без исходного idempotency key.
|
||||
5. Следовать runbook зависимого модуля.
|
||||
|
||||
### Логи содержат секрет/PII
|
||||
|
||||
1. Ограничить доступ и остановить offending export.
|
||||
2. Сохранить только incident metadata, не копировать значение.
|
||||
3. Ротировать скомпрометированный secret.
|
||||
4. Удалить данные по процедуре backend/provider.
|
||||
5. Исправить source redaction + Collector defense; добавить canary test.
|
||||
|
||||
## 17. Проверки и Definition of Done
|
||||
|
||||
- Collector config проходит validate и запускается в едином Compose;
|
||||
- OTLP gRPC и HTTP принимают три сигнала;
|
||||
- все сервисы имеют правильные resource attributes;
|
||||
- request проходит nginx/API/Safety/Open Lines с одним `request_id` и связанным trace;
|
||||
- `ux_session_id` есть только где передан и не является label;
|
||||
- FastAPI/HTTPX/PG/Redis/S3 workers instrumented;
|
||||
- nginx JSON parsing и trace correlation проверены;
|
||||
- Redis/Keycloak/host/Collector metrics доступны;
|
||||
- dashboards и alerts provisioned из versioned files для выбранного telemetry backend; до его выбора это остаётся acceptance/TBD, а не выполненный production DoD;
|
||||
- remote outage, queue full, Collector restart и backend recovery rehearsed;
|
||||
- local profile, если включён, имеет volumes/retention/auth и не публикует порты;
|
||||
- secret/PII canary отсутствует в logs/traces/metrics;
|
||||
- cardinality и sampling tests проходят;
|
||||
- SLO queries воспроизводимы и исключения документированы;
|
||||
- runbooks связаны с alerts.
|
||||
|
||||
## 18. Допущения, TBD и конфликты
|
||||
|
||||
### Решения
|
||||
|
||||
- O1: обязательный архитектурный минимум — Collector; удалённый управляемый OTLP backend является предпочтительным operable-вариантом и остаётся TBD до выбора провайдера.
|
||||
- O2: Prometheus/Grafana/Loki/Tempo — отдельный operable profile, не скрытая обязательная нагрузка основной VM.
|
||||
- O3: JSON stdout — аварийный локальный buffer; audit App DB — durable.
|
||||
- O4: telemetry fail-open для business path, но потеря telemetry alertится.
|
||||
- O5: ID/PII не labels; source redaction обязательна до Collector.
|
||||
|
||||
### TBD
|
||||
|
||||
- O-TBD1: выбрать remote backend/provider, endpoint/auth и стоимость.
|
||||
- O-TBD2: утвердить SLO/RPS/error-budget с product owner.
|
||||
- O-TBD3: legal retention/erasure и допустимость IP/user-agent.
|
||||
- O-TBD4: точные sampling и resource limits после load test.
|
||||
- O-TBD5: поддерживаемый nginx OTEL module и Keycloak native tracing по pinned versions.
|
||||
- O-TBD6: нужен ли local observability profile в первой VM.
|
||||
|
||||
### Обнаруженные архитектурные конфликты
|
||||
|
||||
1. `arch-03` разрешает stdout/platform exporter как минимум, но production-like расследования и alerts без backend ограничены. Здесь remote OTLP backend рекомендован, но не объявлен выбранным: провайдер остаётся TBD.
|
||||
2. `module-05` использует test-only terminal `400` и non-sticky verdict вместо canonical `403`/sticky production verdict. Dashboards обязаны маркировать сервис `stub`; production SLO Safety на нём недостоверен.
|
||||
3. `module-07` — только DB connectivity stub, тогда как arch-01/02 описывают полноценную CRM sync. Dashboard не должен показывать queue/CRM SLI, которых нет.
|
||||
4. Retention, RPO/RTO и production SLO открыты в module-01/04/06/08; значения этого документа являются initial ops policy, не закрывают legal/product TBD.
|
||||
5. Новые observability env (`OTEL_REMOTE_*`, sampling/queue limits) отсутствуют в arch-04; перед реализацией production `.env.example` их нужно добавить туда.
|
||||
|
||||
## 19. Ссылки на прототип и исходные документы
|
||||
|
||||
- VM/Docker logging и firewall: [`../../HAN_chat/deploy/setup-vm-han-chat.sh`](../../HAN_chat/deploy/setup-vm-han-chat.sh).
|
||||
- Прототипный nginx stdout/access log: [`../../HAN_chat/bitrix-local-app/deploy/nginx/nginx.conf`](../../HAN_chat/bitrix-local-app/deploy/nginx/nginx.conf).
|
||||
- Архитектурный observability contract: [`arch-02-api-contracts.md`](arch-02-api-contracts.md).
|
||||
- Compose topology: [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md).
|
||||
Reference in New Issue
Block a user