tasks(vds-migration): decompose umbrella → 3 child tasks

- mssql-vds-migration : Express edition, BACKUP/RESTORE method, mssql.kzntsv.site:1433
- minio-imgproxy-vds-migration : MinIO upgrade 2020→latest, mc mirror, includes imgproxy+nginx
- iis-cutover-to-vds-services 🔵: atomic web.config repoint (1 file → 11 hosts), blocked on both migrations
- umbrella mssql-minio-migration-to-vds 🟢: decomposed (kept for history)

Discovery: 5 prod DBs ≤ 968 MB (Express OK), .ldf logs 12 GB → SHRINKFILE
pre-cutover. VDS: 79 GB free, 5.8 GB RAM avail. ownCloud capped 1G.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-22 09:02:49 +03:00
parent 68706d0bee
commit 86a94d7f9d
4 changed files with 277 additions and 4 deletions

View File

@@ -0,0 +1,77 @@
# mssql-vds-migration
## Goal
Перенести MSSQL контейнер с [[../entities/windows-recovery-host]] на [[../entities/vds-kzntsv]] (`/opt/stacks/databases/mssql/`), Express Edition для прода, доступ снаружи через `mssql.kzntsv.site:1433` (traefik TCP passthrough), интеграция в существующий `vds-backup-rsync-kreknin` pipeline.
Это **MSSQL-only половина** umbrella'ы `mssql-minio-migration-to-vds` (декомпозирована 2026-05-22). Вторая половина — `minio-imgproxy-vds-migration`.
## Key files / refs
- **Source:** docker container `mssql` на windows-recovery-host, image `mcr.microsoft.com/mssql/server:2019-latest`, volume `mssql_mssql_data` (26.6 GB total, real data ~2.4 GB, остальное .ldf logs).
- **Source DBs** (verified via `docker exec mssql ls /var/opt/mssql/data/`, 2026-05-22):
- `MoreThenCms.mdf` 867 MB + log 9.9 GB
- `StayerCalculator.mdf` 504 MB + log 1.2 GB
- `StayerPrice.mdf` 38 MB + log 215 MB
- `TireService.mdf` 8 MB + log 8 MB
- `stostayer.mdf` 968 MB + log 264 MB
- **Max .mdf 968 MB < 10 GB Express limit ✓ all fit**
- **Target:** `/opt/stacks/databases/mssql/{data,docker-compose.yml,.env}` на VDS, паттерн как у postgres (`/opt/stacks/databases/postgres/data` bind, network `proxy` + `shared-dbs`).
- **Image:** `mcr.microsoft.com/mssql/server:2022-latest` Express Edition (`MSSQL_PID=Express`).
- **CMS connection strings:** `Data Source=localhost,1433``Data Source=mssql.kzntsv.site,1433` в IIS web.config / appsettings.
- **TLS:** self-signed, traefik raw-TCP passthrough — pattern [[../.wiki/concepts/db-tls-self-signed-via-traefik-raw-tcp]] + [[../.wiki/concepts/traefik-tcp-passthrough-vs-starttls]].
- **Backup pipeline:** `/opt/stacks/backup/scripts/run.sh` на VDS — добавить новые ноги (см. acceptance 6).
## Decisions
- **Edition: Express** (user 2026-05-22). Max DB size 10 GB соблюдён всеми текущими базами. RAM cap Express = 1.4 GB built-in. Дополнительно `MSSQL_MEMORY_LIMIT_MB=2048` (user-confirmed), но Express всё равно сам зажмёт до 1410.
- **Method: BACKUP DATABASE … WITH COMPRESSION, COPY_ONLY** → scp `.bak` → RESTORE на VDS. Не detach/attach — кросс-edition (Developer → Express) supported только через backup/restore. Compression ≈ 80% reduction, ожидаемый transfer ~500 MB.
- **Pre-cutover SHRINKFILE на .ldf** — срежет 12 GB logs до минимума (не для transfer — для cleanup source перед миграцией; transfer идёт через .bak, который и так не включает inactive log space).
- **Hostname: `mssql.kzntsv.site`** (не `mssql.vds.kzntsv.site` — user decision 2026-05-22). DNS A-record указать на VDS IP.
## Acceptance
1. **Pre-cutover на source** (windows-host):
- `BACKUP LOG <db> WITH TRUNCATE_ONLY` + `CHECKPOINT` + `DBCC SHRINKFILE` для .ldf всех 5 prod DBs.
- Verify `du -sh /var/opt/mssql/data/*_log.ldf` → каждый < 100 MB.
- **WARNING:** SHRINKFILE с TRUNCATE_ONLY ломает log-chain → no point-in-time restore до следующего FULL backup. Делается **только** в migration window, новый FULL снимается сразу после RESTORE на VDS.
2. **MSSQL container на VDS** запущен:
- `mcr.microsoft.com/mssql/server:2022-latest`, `ACCEPT_EULA=Y`, `MSSQL_PID=Express`, `MSSQL_MEMORY_LIMIT_MB=2048`, `SA_PASSWORD` из `pass show mssql-vds/sa-password` (новый pass entry).
- Volume bind `/opt/stacks/databases/mssql/data:/var/opt/mssql:rw`.
- Networks `proxy` + `shared-dbs`. Traefik labels TCP entrypoint `mssql` :1433 → HostSNI(`*`).
3. **Traefik static config** (`/opt/stacks/proxy/traefik/traefik.yml`):
```yaml
entryPoints:
mssql:
address: ":1433"
```
+ ufw allow 1433/tcp.
4. **5 prod DBs restored** на VDS:
- `BACKUP DATABASE … WITH COMPRESSION, COPY_ONLY` на source → 5 `.bak` файлов.
- scp → `/opt/stacks/databases/mssql/data/backups/` на VDS.
- `RESTORE DATABASE … FROM DISK='/var/opt/mssql/backups/<db>.bak' WITH MOVE`.
- Verify `SELECT name, state_desc FROM sys.databases` → все 5 ONLINE, `DBCC CHECKDB('<db>')` → 0 errors на каждой.
5. **CMS connection strings updated** в web.config (или эквиваленте), 8 sites smoke:
- 200 OK + asset loading + admin/assets/getList (известный hot-path).
- **Pre-cutover benchmark обязателен** — admin assets UI / search / catalogs latency измерены до и после, **degradation <2x** target. Если worse — discuss перед commit'ом cutover (10-30ms WAN vs localhost).
6. **Backup pipeline на VDS расширен** (`/opt/stacks/backup/scripts/run.sh`):
- `mssql_dump_full` ежедневно (BACKUP DATABASE WITH COMPRESSION для каждой DB → tar.gz → rsync nightly).
- `mssql_tx_log_backup` ежечасно (BACKUP LOG для каждой DB через `docker exec mssql /opt/mssql-tools/bin/sqlcmd …`) → rsync hourly. **Достигает target RPO 1ч.**
7. **ntfy push verified** для расширенного pipeline (включает MSSQL dump size/duration).
8. **Source windows-host MSSQL** — после 48ч uptime на VDS: stop container (read-only fallback пропустить — pass), через неделю — `docker rm + docker volume rm mssql_mssql_data`.
9. **Documented** в [[../.wiki/concepts/mssql-on-vds]] (создать): architecture, rollback recipe (revert connection strings + start windows-host MSSQL container), migration runbook.
## Open questions
- [ ] **DNS A-record `mssql.kzntsv.site` → VDS IP** (89.253.255.94) — сделать через REGRU API или manual?
- [ ] **Hermes service на windows-host** — зависит от local MSSQL? Если да — мигрируется заодно или ломается. См. [[../.wiki/entities/vds-kzntsv]] Open issues.
- [ ] **CMS connection-string location** — web.config? appsettings? hardcoded в DLL? Если hardcoded — нужен rebuild (build env вопрос). См. note в [[../.wiki/concepts/cms-admin-assets-root-folder-seed]] §"Долгосрочный TODO".
## Risks
- **WAN latency IIS→MSSQL:** 10-30ms vs localhost. Большинство CMS-операций batchey, не latency-sensitive. **Pre-cutover benchmark обязателен** (acceptance 5).
- **Express Edition limits:** 10 GB/DB, 1.4 GB RAM, 1 socket / 4 cores. Max .mdf сейчас 968 MB — запас 10x. Если `stostayer` начнёт расти — early warning через monitoring (separate task).
- **MSSQL Linux compat:** некоторые edge-case T-SQL отличаются (CLR, FileStream, full-text). Smoke обязателен — `EXEC sp_helpdb` + проверить нет ли CLR assemblies / FileStream filegroups в prod DBs.
- **TLS overhead:** raw-TCP через traefik adds <1ms — negligible.
- **VDS RAM tight:** owncloud `anon` 282 MB + gitea 834 MB + verdaccio 226 MB + DBs 285 MB + traefik 52 MB + redis 6 MB = ~1.7 GB реально используется (page-cache reclaimable). MSSQL 2 GB влезает с запасом 4 GB до OOM.
- **Disk free на VDS не проверен** (ops-mcp read-only docker). Нужно ~3 GB MSSQL restored + ~5 GB free для backup'ов. **Проверить `df -h /opt/stacks` ssh'ем перед стартом.**
- **Cutover rollback:** revert возможен только если windows-host MSSQL container оставлен running (read-only желательно но не критично) 48ч после cutover. Acceptance 8 это закладывает.
## Notes
- **Зависит от:** `minio-imgproxy-vds-migration` (нет — независимы).
- **Зависимая follow-up:** списать `cms-stopgap-backup-daily` cron после успешного first VDS backup-pipeline run.
- **Atomic revert (full):** revert CMS web.config → windows-host MSSQL; восстановить cms-stopgap-backup-daily cron; на VDS — `docker compose down -v` для mssql stack; удалить mssql ноги из `run.sh`; remove traefik mssql entrypoint; ufw deny 1433/tcp.