12 KiB
module-10-vm2. Runbook развёртывания ВМ2 Processing
Статус: целевой runbook репозитория ВМ2.
Общий контракт (VPC/SG, PG, S3, ролиdeploy, TLS процедура, порядок cutover) —arch-10-deployment.md.
ВМ1 —module-10-deployment-vm1.mdи её fresh production runbook. Не переносить команды ВМ1 и не шарить Compose/IAM/secrets.
1. Границы
ВМ2 владеет nginx public 80/443 (только exact CRM webhook) и private 8443 (Message Safety), message-safety API/worker, clamd/freshclam, bitrix-sync, Redis Safety, Collector. Guest API, Keycloak, SPA и SMS callback здесь не разворачиваются.
<BACKEND_ROOT> / <BACKEND_REPO_URL> — репозиторий ВМ2. Public ACME host — <PROCESSING_PUBLIC_HOST>. Private DNS processing.internal не публикуется.
2. Sizing и load gates
Начальный sizing без local Grafana: 4 vCPU, 8 ГБ RAM, 80 ГБ SSD, 4 ГБ swap; Redis 512 МиБ; Collector 512 МиБ + 5–10 ГБ queue; свободный диск ≥30%.
До real traffic — load test module-05 §15.4:
- sustained 10 text checks/s: p95 ≤2 с, p99 ≤5 с;
- sustained 2 file checks/s на 5 worker slots: среднее processing ≤2.5 с, p95 ≤60 с, public wait ≤300 с;
- 100 pending принимаются; 101-й file POST — retryable
503без новой task; - RPS overflow —
429 + Retry-After; - long Safety poll не блокирует WS/read API ВМ1;
- если gate не пройден — увеличить slots/CPU/clamd scan lanes; production traffic не открывать.
Monthly availability SLO Safety в MVP не задаётся. Scale-out/ВМ3: sustained CPU/RAM >70%, queue age >30 с, провал performance gates, contention bitrix-sync или независимый release cadence. Workers масштабируются первыми по queue depth, clamd — scan lanes.
3. Hardening и egress
Arch-10 §5 / arch-06. Public Docker ports — 80,443. Private 8443 не internet SG.
Default-deny egress. Bootstrap window для registry/OS, затем закрыть. Оставить: S3, approved Bitrix portal (bitrix-sync), signature CDN (freshclam), DNS/NTP, SigNoz 4317, PG. Постоянный open egress запрещён.
Отдельный IAM principal Selectel: только VM2 secret names.
4. Release layout и .env ВМ2
Checkout exact SHA. Структура: root Compose, nginx, Safety, bitrix-sync, Redis Safety, observability. Frontend-static нет.
Секреты ВМ2 (не в .env ВМ1):
- PG DSN роли Safety/
bitrix_sync+ CA; MESSAGE_SAFETY_REDIS_URL;- Safety mode file
/etc/han-chat/message-safety-mode.env(не repository.env); - S3 read-only quarantine credentials;
- internal TLS PEM
8443; - Bitrix sync webhook tokens, portal credentials,
BITRIX_WEBHOOK_ALLOWED_CIDRS; - OTEL exporter secrets.
BITRIX_SYNC_ENABLED=false до §9. Paired tokens local app ВМ1 здесь не живут.
5. Images
Один immutable image API+worker Safety, отдельные containers. MVP: 1 API + 1 worker с 5 file-worker slots. Build без production secrets. Frontend на ВМ2 не собирается.
6. Root Compose ВМ2
Сервисы: public/private nginx, message-safety-api, message-safety-worker, clamd, freshclam, bitrix-sync, Redis Safety, local otel-collector.
Networks: public (только nginx webhook/ACME), backend, egress (freshclam, bitrix-sync, Safety worker → S3/PG/DNS, collector → SigNoz), observability. Safety API/clamd/Redis без общего internet egress.
Volumes: Redis Safety data (rebuildable), ClamAV signatures, ACME public, otel-queue + init. Frontend-static нет. Published: nginx 80/443; 8443 только SG ВМ1/ops.
Compose gate — arch-10 применительно к этому Compose.
7. TLS ВМ2
Public: arch-10 §9, -d <PROCESSING_PUBLIC_HOST>. HTTP webhook paths — без redirect с query token (module-03-nginx-vm2.md).
Private 8443: сертификат internal CA, SAN = private DNS. Не Let's Encrypt. Caller ВМ1 проверяет CA bind.
8. Миграции Safety
Stub не создаёт PG tables. Production v2: schema message_safety, lease/fencing smoke. Первая migration создаёт config_versions и seed version 1; readiness без ровно одной valid active version не открывается.
Config-only rollout — отдельный root-owned job под config-admin role: immutable draft, JSON Schema, artifacts, approvals, транзакционный activate. Runtime — только SELECT к config. Rollback не реактивирует retired row: клон в новую monotonic version.
9. Controlled rollout bitrix-sync
До BITRIX_SYNC_ENABLED=true:
- custom Contact fields и env names; universal CRM
UF_CRM_<digits>→ufCrm_<digits>; - smart process конфликтов и
bitrix_sync.settings; - входящий webhook техпользователя, права module-07 §13;
- два HTTP-webhook на
https://<PROCESSING_PUBLIC_HOST>/bitrix/sync/webhook/...?token=...; query/body не в журналах; local app handler не создавать; - expand migrations
han_app(делает ВМ1/api-backend) затемbitrix_sync; GRANT и negative tests; cutover_watermark; отменить pending до него сinitial_full_sync_cutover;- не создавать backfill;
- image с sync disabled:
/health/live,sync_disabled, smoke Bitrix methods; - открыть на nginx ВМ2 только два exact routes для
BITRIX_WEBHOOK_ALLOWED_CIDRS; valid/invalid source IP; нет запросов на ВМ1; - включить sync; canary post-watermark; нет CRM ID в App DB;
- canary window: queue age, 429, DLQ, webhook lag, reconciliation, source-IP rejects.
Rollback: закрыть webhook или 503; BITRIX_SYNC_ENABLED=false; ВМ1 не изменяется; mapping не удалять; schema не downgrade.
Изменение source IP Битрикс24
Сигнал: всплеск Contact из reconciliation + webhook_rejected_total{reason="source_ip"}.
- Сопоставить bounded-retention журнал rejects; query/body не извлекать.
- Подтвердить адрес как инфраструктуру Битрикс24; query token сам по себе недостаточен.
- Минимальный CIDR в version-controlled allow-list, review,
nginx -tчерез deployment unit. - Safe reload; приём webhook без query/body в logs.
- Rejects прекратились, lag нормализовался.
- Ошибочное расширение — rollback allow-list. Автодобавление IP запрещено.
10. Ordered startup ВМ2
- Redis Safety,
otel-queue-init, Collector; clamd/freshclam, Safety API/worker,bitrix-sync;- nginx последним: оба TLS, exact webhook, capability health, signature age, negative ingress/egress.
До enablement bitrix-sync — sync_disabled. Safety v2 capability text|links|files|worker. Redis Safety не core gate readiness.
11. Public smoke ВМ2
curl -I http://<PROCESSING_PUBLIC_HOST>/
curl -i https://<PROCESSING_PUBLIC_HOST>/internal/sync/v1/status
curl -i https://<PROCESSING_PUBLIC_HOST>/bitrix/sync/webhook/contact
openssl s_client -connect <PROCESSING_PUBLIC_HOST>:443 -servername <PROCESSING_PUBLIC_HOST>
Expected: HTTP redirect/ACME policy; internal 404; GET webhook 405/404; отдельный cert. POST webhook — отдельный form-urlencoded test allowed/denied IP без query token в history.
Private 8443 проверяется с ВМ1/ops, не из интернета.
12. Observability ВМ2
module-09-observability-vm2.md + arch-07. Paging: MOCK, Safety config, sync DLQ, queue age.
13. Cutover, rollback, reprovision
Cutover gates: private TLS chain/SAN; Safety v2 PG migration и lease/fencing smoke; capability text|links|files|worker; S3 Gate 4 (Safety read-only); performance §2; egress negative tests. Approvals: Safety Service, Rule Pack, Security, Product, Operations. Только после них ВМ1 переключает MESSAGE_SAFETY_URL.
При потере ВМ2 fail-open запрещён. Reprovision из immutable image; отдельный IAM; Redis пустой; gates повторяются. RTO ≤4 ч; restore rehearsal ≥2 раза в год.
Rollback ВМ2 не требует изменения nginx ВМ1. Caller rollback — runbook ВМ1.
14. Emergency MOCK и Freshclam
deploy без root login:
sudo /usr/local/sbin/han-message-safety-mode mock --text-free true --file-free true
sudo /usr/local/sbin/han-message-safety-mode mock --text-free true --file-free false
sudo /usr/local/sbin/han-message-safety-mode mock --text-free false --file-free true
sudo /usr/local/sbin/han-message-safety-mode mock --text-free false --file-free false
sudo /usr/local/sbin/han-message-safety-mode standard
Helper root:root 0755; sudoers только этот executable. Config root:han-message-safety 0640, GID 10001. Нет auto-expiry; incident не закрывать без standard и canary. File в MOCK — scan_status=bypassed, не clean. deploy не пишет Compose/Docker.
freshclam: controlled egress только к signature CDN. Seed max_signature_age_hours=240, schema max 720. Stale/failed update выключает только files и alert. Новая база — integrity/EICAR, atomic activate; regression — предыдущая валидная база.
15. Rollback, ops, incidents ВМ2
Redis Safety restore — empty/clean, lazy cache (module-04-redis-vm2.md). Routine: signature age, Safety queue, sync DLQ/webhook lag, Collector, disk, egress still deny.
Incident: Safety timeout — checkpoint, не новый task id; Bitrix down — circuit/DLQ, webhook 503; MOCK page — вернуть standard; cert processing host и private CA.
Потеря ВМ2: новая VM в VPC, hardening, private DNS, secrets из VM2 IAM, empty Redis, Safety migrations, nginx webhook+8443, не менять public routes ВМ1 до готовности; затем повторить cutover gates.
16. Definition of Done ВМ2
Дополнительно к arch-10 §12:
- Compose/nginx/Redis Safety/Collector прошли профильные compose/nginx gates;
- private
8443fail-closed до cutover, затем только источники ВМ1; - webhook allow-list и preflight
BITRIX_SYNC_ENABLEDсогласованы; - capability/load gates module-05;
- MOCK helper и Freshclam rehearsal;
- observability ВМ2 + redaction (нет query/body/file content);
- cutover §13 не объявлен выполненным только документацией.
17. TBD ВМ2
D-TBD5 Safety v2; D-TBD6 bitrix-sync cutover; performance gates уже в §2.
18. Ссылки
- Контракт:
arch-10-deployment.md. - ВМ1:
module-10-deployment-vm1.md. - Исполняемый fresh production runbook ВМ1:
RUNBOOK.production.ru.md. - Исполняемый runbook ВМ2:
RUNBOOK.ru.md. - Safety / sync / nginx:
module-05-message-safety.md,module-07-bitrix-sync.md,module-03-nginx-vm2.md.