- deleted .tasks/windows-host-fallback-backup-daily.md (MSSQL removed on decommission 2026-06-08) - recovery-architecture-snapshot.md: marked ИСТОРИЧЕСКАЯ ЗАПИСЬ; removed 3 broken [[wiki-links]] (cms-server-port-leak-fix, cms-admin-assets-root-folder-seed, webconfig-password-xml-escape) - snolla-recovery-vm.md: marked УДАЛЕНА 2026-06-08 - ruvds-iis-host.md: struck 2 resolved risks (imgproxy SPOF, LE renewal); cross-ref winacme - future-resilient-architecture-goals.md: dead task link → plain text - mssql-on-vds.md: frontmatter fix; Backup TODO section replaced with implemented block (Express COPY_ONLY, sqlcmd, bind-mount pattern) - vds-kzntsv.md: added MSSQL row to software stack table - log.md: update entries for lint + mssql backup implementation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
260 lines
21 KiB
Markdown
260 lines
21 KiB
Markdown
---
|
||
title: Future Resilient Architecture — roadmap
|
||
type: concept
|
||
tags: [planning, architecture, resilience, roadmap]
|
||
sources: [../sources/nas-recovery-session-2026-05-18.md]
|
||
updated: 2026-05-21
|
||
---
|
||
|
||
# Future Resilient Architecture
|
||
|
||
Roadmap "выстроить отказоустойчивую архитектуру чтобы инциденты типа 2026-05-18 не повторялись". Документ **живой** — переоценивается после каждого incident'а и major-migration'а.
|
||
|
||
Структура:
|
||
- **§Workshop pass 1 (2026-05-21)** — текущий зафиксированный план, decisions per service. Это **canonical** часть документа.
|
||
- **§Pre-workshop placeholder (2026-05-19)** — изначальные наброски без user-confirmation, оставлены для history. Не source of truth.
|
||
|
||
## Workshop pass 1 — 2026-05-21
|
||
|
||
Roadmap expanded from placeholder to concrete decisions + impl-tasks. Workshop session с user (vitya) 2026-05-21. Каждое decision ниже = user-confirmed, не unilateral recommendation. Trace разговора зафиксирован в `[resilience-roadmap-design]` close-note (см. `.tasks/STATUS.md`).
|
||
|
||
### Per-service RTO/RPO matrix
|
||
|
||
Globальные RTO/RPO разнесены **per service** — cost-of-downtime у разных сервисов разный. Числа = target, не факт. Откалибруются после first incident в новой архитектуре.
|
||
|
||
| Сервис | RTO (max downtime) | RPO (max data loss) | Rationale |
|
||
|---|---|---|---|
|
||
| **CMS прод-сайты** (snolla/labtools/pilorama98/tandemmebel/emspb/kupimknigi/maljarka — 8 hosts) | **4 ч** | **1 ч** | клиентский трафик = деньги; больше 4ч → звонки клиентов |
|
||
| **CMS DB (MSSQL)** | **4 ч** | **1 ч** | orders + контент; час правок переживёшь, день — нет |
|
||
| **CMS content** (IIS files `C:\sites\*` + MinIO) | **4 ч** | **24 ч** | картинки/asset'ы меняются редко |
|
||
| **OpenWRT router** | **1 ч** | n/a | сетевой SPOF — без него весь public IP мёртв, tied к CMS |
|
||
| **Traefik** (на windows-host) | **4 ч** | n/a | живёт на том же host'е что CMS, RTO одинаковый |
|
||
| **Gitea** | **8 ч** | **24 ч** | один пользователь, полдня без push переживёшь |
|
||
| **Verdaccio** | **8 ч** | **24 ч** | без деплоев фронтов полдня — ок |
|
||
| **Registry** | **24 ч** | **n/a** (rebuild) | "новых наделаю" decision при VDS bootstrap, см. [[../sources/vds-kzntsv-bootstrap-2026-05-20]] §3.3 |
|
||
| **Shared DB-park** (PG/Maria/Mongo/Redis на VDS) | **8 ч** | **24 ч** | dev/staging, не прод-трафик |
|
||
| **ntfy** | **4 ч** | n/a | алерт-канал; без него слепой но не сломанный |
|
||
|
||
**Decisions зафиксированы (что отвергнуто):**
|
||
- **99.99% uptime / continuous replication / hot-standby для CMS** — отвергнуто как непропорционально дорогое для one-person infra.
|
||
- **MSSQL Always-On AG** — отвергнуто (требует Enterprise license), log shipping каждые 60 мин достаточно для RPO 1ч.
|
||
- **MSSQL → PostgreSQL миграция** — оставлено как long-term option (упомянуто в §Pre-workshop placeholder), не приоритет — отдельный major project, требует CMS-side rewrite.
|
||
|
||
**Калибровочные факты:**
|
||
- 2026-05-18 incident: RTO факт = 15 ч, RPO факт = 9 дней (Hyper Backup от 2026-05-09).
|
||
- Target 4ч / 1ч для CMS = **огромный шаг** от текущей baseline.
|
||
- Прогресс 2026-05-20: VDS поднят → infra (gitea/verdaccio/registry/DB-park) уже decoupled с windows-host SPOF. CMS — пока нет.
|
||
|
||
### CMS backup pipeline — 2-фазный план
|
||
|
||
**Текущий статус (2026-05-21):** CMS прод (sites + MSSQL + MinIO) на [[../entities/windows-recovery-host]] **не имеет ни одного бэкапа нового состояния** — последний Hyper Backup 2026-05-09 был с мёртвой синки. RPO факт = ∞ (если host сгорит сейчас — теряем всё).
|
||
|
||
**Фаза 1 — stop-gap (1-2 дня работы, на этой неделе):**
|
||
Impl-task: `windows-host-fallback-backup-daily` (🟢 closed 2026-05-24, декоммишнен 2026-06-11).
|
||
- MSSQL: ежедневный `BACKUP DATABASE FULL` → локальный `D:\backup\` → ночной rsync на [[../entities/kreknin-synology]]
|
||
- IIS files (`C:\sites\*`): ежедневный rsync → kreknin
|
||
- MinIO data dir: ежедневный rsync → kreknin
|
||
- Cron через Windows Task Scheduler + SSH-pipe (паттерн как у [[../../.tasks/vds-backup-rsync-kreknin]])
|
||
- Достигаемый RPO = 24ч (плохо vs target 1ч, но **лучше чем ∞** и достаточно как мост до Фазы 2)
|
||
- **Не строить ничего изощрённого** — это патч на 2-4 недели до миграции MSSQL/MinIO.
|
||
|
||
**Фаза 2 — proper RPO 1ч после миграции на VDS (1-2 недели работы):**
|
||
Impl-task: [[../../.tasks/mssql-minio-migration-to-vds]].
|
||
- MSSQL container на [[../entities/vds-kzntsv]] как часть `/opt/stacks/databases/` рядом с pg/maria/mongo/redis
|
||
- MinIO контейнер на VDS отдельным stack'ом `/opt/stacks/storage/`
|
||
- CMS app в IIS на windows-host ходит через TCP на `mssql.vds.kzntsv.site:1433` / `minio.vds.kzntsv.site:9000` — connection strings меняются, остальное прозрачно (паттерн уже работает для DBs через traefik raw-TCP, см. [[traefik-tcp-passthrough-vs-starttls]] + [[db-tls-self-signed-via-traefik-raw-tcp]])
|
||
- Backup pipeline = расширение **существующего** `/opt/stacks/backup/scripts/run.sh` на VDS: добавить `sqlcmd BACKUP LOG` ежечасно + ежедневный full в существующий rsync-pipeline к kreknin
|
||
- **Достижение RPO 1ч** = tx log backup каждые 60 мин (или 15 — tunable)
|
||
- **Risk:** сетевая латентность IIS→MSSQL теперь WAN (10-30ms vs localhost). Большинство CMS-операций batchey, не latency-sensitive — но **pre-cutover benchmark обязателен** для hot-paths (admin assets UI / search / каталоги).
|
||
|
||
**Stop-gap pipeline списывается после Фазы 2** — backup data будет идти через VDS-pipeline.
|
||
|
||
### IIS migration track
|
||
|
||
**Текущий статус:** IIS на [[../entities/windows-recovery-host]] — temp-solution recovery 2026-05-19 (изначально recovery-host был VM, переехали на native IIS host для стабильности — см. [[../sources/iis-host-migration-2026-05-19]]). Домашняя машина = SPOF + физический риск (пожар / залив / кража / power-loss).
|
||
|
||
**Target end-state (долгосрочный):** snolla CMS переписан на node → IIS не нужен вообще, всё в docker на VDS. Это **dev-работа**, вне scope этой roadmap'ы. Прогресс отслеживается отдельно user'ом.
|
||
|
||
**Переходный план:** managed Windows hosting (RU-провайдер), куда переедет IIS до завершения node-rewrite'а.
|
||
|
||
Impl-task (research-only): [[../../.tasks/windows-hosting-vendor-research]] (1 день).
|
||
- Output: 1-pager с recommended vendor + plan / cost estimate / migration recipe outline.
|
||
- Comparison candidates: Rusonyx (у тебя уже там VDS), Selectel, FirstVDS, Beget.
|
||
- Critical constraints: RDP-доступ, .NET Framework 4.8 native, IIS 10, external MSSQL/MinIO connectivity (на VDS после Фазы 2).
|
||
|
||
После research → файлим follow-up impl-task `iis-migration-to-managed-windows-hosting` (большая, mes+ работы) — но **не сейчас**, пока на windows-host'е работает + stop-gap backup'ы плюсуют RPO 24ч safety net.
|
||
|
||
### Cloud off-site backup target (3-й уровень 3-2-1)
|
||
|
||
**Recommendation (не файлится impl-таской пока):** **Yandex Object Storage** (~1.6₽/GB/мес Standard tier, S3-compatible — работает с restic / rclone / duplicati). РФ-юрисдикция → нет cross-border сюрпризов.
|
||
|
||
**Альтернатива rejected:** Backblaze B2 — дешевле (~$5/TB/мес) но cross-border payment friction + sanctions risk.
|
||
|
||
**Defer impl:** [[../entities/kreknin-synology]] уже географически off-site (другая локация). Cloud добавится **поверх** kreknin'а, когда захочется паранойи "kreknin тоже может сгореть" или после первого incident'а где kreknin не помог. До этого: kreknin = "1 off-site" из 3-2-1.
|
||
|
||
**Future impl-task:** `cloud-offsite-backup-yandex-object` — ⚪ ready (не file'нута), создать когда руки дойдут.
|
||
|
||
### Network resilience
|
||
|
||
**Recommendation (не файлится impl-таской):** **defer multi-WAN.** Провайдер исторически стабилен. OpenWRT mwan3 + 4G/LTE USB-modem = страховка ~3-5к₽ единоразово + симка ~200₽/мес, но low-probability event. Возвращаемся после первого incident'а с потерей провайдера.
|
||
|
||
**Cloudflare Tunnel** (free tier, IP-абстракция, no DDoS-protection): отдельный вопрос для workshop pass 2 — добавляет vendor dependency на edge, trade-off обсуждается отдельно когда станет интересно (особенно после миграции MSSQL/MinIO на VDS — тогда windows-host станет thin web-layer, легче абстрагировать его IP).
|
||
|
||
**Future impl-tasks (не file'нуты):**
|
||
- `network-mwan3-4g-failover` — ⚪ ready, file когда подгорит провайдером
|
||
- `cloudflare-tunnel-edge-abstraction` — workshop pass 2 решение
|
||
|
||
### Monitoring stack
|
||
|
||
**Recommendation (не файлится impl-таской, но приоритет high среди not-filed):** **Uptime Kuma на VDS.** Docker, ставится за 30 мин на `/opt/stacks/monitoring/`, push-нотификации через ntfy (уже работает `vds-ops` topic — см. [[../../.tasks/vds-ntfy-push]]). Покрывает HTTP/TCP/ping/DNS healthchecks + cert-expiry warnings.
|
||
|
||
**Anti-recommend:** Prometheus + Grafana — overkill для one-person infra, full-stack observability нужен когда 20+ сервисов. Внешний (Pingdom/UptimeRobot) — платный, лучше self-host раз VDS уже есть.
|
||
|
||
**Initial monitor set (для impl):**
|
||
- HTTP 200 OK на 8 CMS hosts (snolla.com, labtools.ru/pro, pilorama98.ru, tandemmebel.ru, emspb.ru, kupimknigi.spb.ru, maljarka.tandemmebel.ru)
|
||
- HTTP 200 на инфра-hosts: git.kzntsv.site, verdaccio.kzntsv.site, registry.kzntsv.site, ntfy.vds.kzntsv.site
|
||
- TCP на DB-park ports: postgres/mariadb/mongo/redis (5432/3306/27017/6379)
|
||
- Ping на windows-recovery-host (94.19.247.14) и VDS (89.253.255.94)
|
||
- Cert-expiry warnings (Uptime Kuma встроено)
|
||
|
||
**Желательно установить ДО** того как windows-host опять упадёт — чтобы инцидент был "ntfy push 2 мин назад", а не "мне Серёга позвонил".
|
||
|
||
**Future impl-task (не file'нута):** `monitoring-uptime-kuma-deploy` — ⚪ ready, **приоритет high** среди not-filed.
|
||
|
||
### Runbook coverage matrix
|
||
|
||
**Текущее покрытие** (post-mortem chronologies с step-by-step recipe):
|
||
- [[../sources/nas-recovery-session-2026-05-18]] — NAS-loss recovery
|
||
- [[../sources/iis-host-migration-2026-05-19]] — IIS migration recipe
|
||
- [[../sources/vds-kzntsv-bootstrap-2026-05-20]] — VDS bootstrap
|
||
|
||
**Missing runbooks:**
|
||
- VDS-loss recovery (если Rusonyx упал / аккаунт потерян)
|
||
- Cert-expiry (acme.json renewal failure, manual DNS-01 через REGRU)
|
||
- DB-corruption restore (per-service: MSSQL, postgres, mariadb, mongo)
|
||
- Ransomware-recovery (encrypted backups restore protocol)
|
||
- OpenWRT-loss (новый роутер, restore configs)
|
||
|
||
**Defer:** runbook'и для **текущей** переходной архитектуры устареют через 2 мес (после `mssql-minio-migration-to-vds` + `iis-migration-to-managed-windows-hosting`). Пишем после стабилизации архитектуры — иначе тратим время на документацию которая не доживёт до использования.
|
||
|
||
**Future impl-task (не file'нута):** `runbook-coverage-matrix-design` — ⚪ ready, file **после** migrations завершены.
|
||
|
||
### Top-3 impl-tasks filed (2026-05-21)
|
||
|
||
1. **[[../../.tasks/cms-stopgap-backup-daily]]** ⚪ — Фаза 1, plug RPO=∞ за 1-2 дня.
|
||
2. **[[../../.tasks/mssql-minio-migration-to-vds]]** ⚪ — Фаза 2 enabler, achieves RPO 1ч target.
|
||
3. **[[../../.tasks/windows-hosting-vendor-research]]** ⚪ — design-task для IIS-переезда (1 день research, output = recommendation + cost).
|
||
|
||
### Workshop pass 2 — open agenda
|
||
|
||
Что **не** обсуждалось в этом проходе (для следующего workshop'а когда руки дойдут):
|
||
- Cloudflare Tunnel — edge abstraction trade-off
|
||
- Off-site cloud target — конкретный configure (decision уже сделано, ждёт kreknin-incident'а или паранойи)
|
||
- Hermes service — defer, ждёт уточнения user
|
||
- snolla node-rewrite progress — dev-track, периодически переоценивать impact на этот roadmap (если близко к completion → managed Windows hosting миграция отменяется)
|
||
- DR drill cadence — failover тесты раз в квартал (упомянуто в §Pre-workshop placeholder, не закрыто)
|
||
|
||
---
|
||
|
||
## Pre-workshop placeholder (2026-05-19) — historical draft
|
||
|
||
> **Note:** ниже — изначальные наброски до workshop pass 1. Не source of truth, оставлены для history. Concrete decisions — в §Workshop pass 1 выше.
|
||
|
||
## Что сейчас не так
|
||
|
||
См. [[recovery-architecture-snapshot]] → раздел "Single Points of Failure". Кратко:
|
||
|
||
- ⚠️ Windows-PC = SPOF
|
||
- ⚠️ Один public IP
|
||
- ⚠️ Один MSSQL primary без replica
|
||
- ⚠️ Один MinIO single-node
|
||
- ⚠️ Backup только Hyper Backup на одну синку (Kreknin), сейчас она cold
|
||
- ⚠️ Backup нового рабочего состояния (CMS data на recovery-host) **отсутствует**
|
||
- ⚠️ Нет off-site backup (cloud)
|
||
|
||
## Цели верхнего уровня
|
||
|
||
1. **RTO** (Recovery Time Objective) — сколько максимум **downtime** клиенты должны видеть при отказе.
|
||
- Текущий по факту: ~15 часов (что и было).
|
||
- Целевой: **< 1 час** для одиночного отказа, **< 4 часов** для каскадного.
|
||
2. **RPO** (Recovery Point Objective) — сколько максимум **данных потерять** при отказе.
|
||
- Текущий: до 24 часов (если успеет бэкап после изменения) — больше если бэкап не успел.
|
||
- Целевой: **< 1 час**, в идеале continuous (replication).
|
||
3. **Стоимость** — bounded by разумным % от выручки клиентов.
|
||
4. **Operational simplicity** — никаких heroic ops по 15 часов в случае проблемы.
|
||
|
||
## Технические направления (наброски)
|
||
|
||
### Backup-стратегия 3-2-1
|
||
|
||
Стандарт: **3** копии данных, **2** разных media, **1** off-site.
|
||
|
||
- **Копия 1:** primary storage (live) на NAS / Windows-PC
|
||
- **Копия 2:** local backup target ([[kreknin-synology]] остаётся, плюс отдельный)
|
||
- **Копия 3:** **cloud off-site** — Backblaze B2 / Yandex Object Storage / AWS S3 Deep Archive / Hetzner Storage Box
|
||
- Все backups encrypted client-side
|
||
- Retention: 7 daily / 4 weekly / 12 monthly
|
||
|
||
### Compute resilience
|
||
|
||
Варианты:
|
||
|
||
A. **Multi-host on-prem:** 2-3 физических машины с виртуализацией (Proxmox VE), HA-кластер, VMотом migration. Дорого, но автономно.
|
||
|
||
B. **Cloud-first:** перенос CMS-стека в managed Kubernetes (Yandex Cloud / VK Cloud / hetzner) — managed MSSQL / managed S3 / managed Postgres. Простота операций, но vendor lock-in.
|
||
|
||
C. **Гибрид:** primary on-prem (Synology с CMR), warm standby в cloud (готовый к failover за 5 мин). Compromise.
|
||
|
||
### Database resilience
|
||
|
||
MSSQL options:
|
||
- **Always On Availability Groups** (требует Enterprise license — недёшево)
|
||
- **Log Shipping** (бесплатно, но manual failover)
|
||
- **MSSQL → PostgreSQL миграция?** (если есть полная свобода — выгоды Open Source + распространённые managed предложения).
|
||
|
||
Для recovery-сценария: **continuous backup** через VDI + native MSSQL TDE backup → S3.
|
||
|
||
### Network resilience
|
||
|
||
- **Multi-WAN на OpenWRT:** primary провайдер + 4G/LTE USB-modem как failover. OpenWRT mwan3 package.
|
||
- **Cloudflare Proxy / Tunnel:** перенаправление публичного трафика через Cloudflare edge. Помогает с DDoS и переключением IP без DNS-changes.
|
||
- **Static IP пересмотр:** разные провайдеры → multi-homed setup.
|
||
|
||
### Monitoring + auto-recovery
|
||
|
||
- **Healthchecks** на каждый layer (TCP, HTTP, deep DB query) — Prometheus + Alertmanager или Uptime Kuma.
|
||
- **Watchdog скрипты** — auto `ipconfig /release/renew` в VM, auto `docker compose restart` контейнера если healthcheck падает > N min.
|
||
- **Telegram-уведомления** на инциденты (для пользователя в реал-тайм когда что-то фейлится).
|
||
|
||
### Документация и runbook
|
||
|
||
- Runbook на каждый процедурный сценарий (failover, restore, network swap).
|
||
- Регулярные **failover drills** раз в квартал — буквально нажать "восстановиться" и засечь время.
|
||
- Wiki эта — стартовая точка.
|
||
|
||
## Что НЕ цели
|
||
|
||
- Перестройка с нуля «потому что сейчас не идеально». Текущая архитектура работает, замена должна быть инкрементальной.
|
||
- 99.99% uptime — нереалистично для one-person infrastructure, и не нужно для CMS-сайтов клиентов.
|
||
|
||
## Следующие шаги (когда дойдут руки)
|
||
|
||
1. Заменить WD40EFAX на CMR-диски, пересобрать пул [[dead-synology-diskstation]].
|
||
2. Включить ежедневный Hyper Backup из нового пула на [[kreknin-synology]].
|
||
3. Добавить cloud-backup target (Yandex Object Storage наиболее очевидный для RU-юрисдикции).
|
||
4. Настроить monitoring/alerts.
|
||
5. Документировать runbooks.
|
||
|
||
Связано со всеми остальными страницами этого wiki.
|
||
|
||
## Прогресс 2026-05-20
|
||
|
||
✅ **Decouple инфра-сервисов от windows-recovery-host SPOF.** Поднят отдельный облачный VDS [[vds-kzntsv]] (Rusonyx 160 NVMe), туда мигрированы gitea / verdaccio / docker-registry + shared DB park (Postgres/MariaDB/Mongo/Redis). [[windows-recovery-host]] теперь хостит **только** production CMS. Это не полный multi-host resilience (VDS сам по себе SPOF), но critical infra decoupling сделан.
|
||
|
||
Запланированы follow-up tasks (см. `.tasks/`):
|
||
- `vds-backup-rsync-kreknin` — ежедневный 05:00 MSK rsync VDS → kreknin с email-нотификацией.
|
||
- `vds-ntfy-push` — self-hosted push на Android для backup status и monitoring.
|
||
- `vds-gc-cron` — cron GC для verdaccio + registry чтобы не повторился incident 99G на registry.
|
||
|
||
Следующая фаза по originally outlined ladder — добавить **cloud off-site backup target** (Backblaze B2 / Yandex Object Storage) поверх kreknin'а, и replicated MSSQL для production CMS.
|