# 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 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/.bak' WITH MOVE`. - Verify `SELECT name, state_desc FROM sys.databases` → все 5 ONLINE, `DBCC CHECKDB('')` → 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.