mssql+minio vds migration done — IIS snolla cutover live
- mssql-vds-migration 🟢: Express 2022 Linux на mssql.kzntsv.site:1433, 5 DBs restored (schema 2019→2022 auto-upgrade), 8 prod hosts 200 OK - minio-imgproxy-vds-migration 🟡: stack live, 3 GiB / 19324 obj mirrored (2020→2025 upgrade via S3 API), DNS swap imgproxy.kzntsv.site pending - iis-cutover-to-vds-services 🟡: 1 web.config edit catch-all для 11 hosts; MinIO leg pending DNS swap (URLs уже через imgproxy.kzntsv.site domain) - 3 wiki concepts: mssql-on-vds, minio-imgproxy-on-vds, index updated Findings: (1) server logins НЕ переезжают в .bak — orphan fix manual, (2) traefik recreate-not-restart для port mapping change, (3) PowerShell не вызывает pass bash-script (NULL pw → misleading auth fail), (4) mc 2025 не auto-creates target buckets, (5) non-ASCII filename silent skip в mc mirror — verify по count+size обязательно. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# Admin Task Board
|
||||
_Updated: 2026-05-22 (mssql-minio-migration-to-vds декомпозирована → 3 child tasks: `mssql-vds-migration` ⚪ + `minio-imgproxy-vds-migration` ⚪ + `iis-cutover-to-vds-services` 🔵. Discovery: 5 prod DBs все ≤ 968 MB <10 GB Express OK; .ldf logs 12 GB → SHRINKFILE pre-cutover; MinIO 3 GB + image 2020 (CVE) → upgrade + `mc mirror`; imgproxy stack едет вместе. **IIS cutover — финальный шаг ради которого всё затевалось**: 11 CMS hosts через snolla catch-all = atomic edit одного web.config. VDS: 79 GB disk free, 5.8 GB RAM available, ownCloud mem_limit 1G applied.)_
|
||||
_Updated: 2026-05-22 (MSSQL+MinIO миграция выполнена за одну сессию: MSSQL Express 2022 live на `mssql.kzntsv.site:1433` с 5 restored DBs, IIS snolla site cutover ✓ — 8 prod hosts 200 OK; MinIO stack live на VDS, 3 GiB / 19324 obj mirrored с upgrade 2020→2025 ✓ — ждёт DNS swap `imgproxy.kzntsv.site` от user. 3 wiki concepts ingested. 48ч soak до decommission source containers 2026-05-24.)_
|
||||
|
||||
<!--
|
||||
Status legend:
|
||||
@@ -530,37 +530,96 @@ Original umbrella `.tasks/mssql-minio-migration-to-vds.md` сохранён дл
|
||||
|
||||
---
|
||||
|
||||
## ⚪ [mssql-vds-migration] — Перенести MSSQL с windows-recovery-host на vds-kzntsv. Express edition (prod, 10 GB/DB limit OK для всех 5 prod DBs), `mssql.kzntsv.site:1433` через traefik TCP passthrough.
|
||||
## 🟢 [mssql-vds-migration] — DONE 2026-05-22: MSSQL Express 2022 live на `mssql.kzntsv.site:1433`, 5 DBs restored + IIS snolla site cutover ✓
|
||||
|
||||
Method: BACKUP DATABASE WITH COMPRESSION, COPY_ONLY → scp → RESTORE на VDS. Кросс-edition (Developer→Express). Pre-cutover SHRINKFILE на .ldf срежет 12 GB logs (warning: ломает log-chain до следующего FULL — приемлемо в migration window).
|
||||
**Closed:** 2026-05-22 — phase 1 (deploy + restore + cutover) complete; 8 prod hosts 200 OK через VDS MSSQL. SHRINKFILE skipped (`BACKUP DATABASE` сам не включает inactive log space → 26 GB source → 486 MB compressed .bak).
|
||||
|
||||
**Status:** ready
|
||||
**Where I stopped:** (not started)
|
||||
**Next action:** См. `mssql-vds-migration.md` — full acceptance (9 items) + risks + open questions. Sub-phases: (1) SHRINKFILE cleanup на source, (2) BACKUP 5 DBs → scp → RESTORE на VDS, (3) traefik TCP entrypoint :1433 + ufw, (4) DNS A `mssql.kzntsv.site`, (5) CMS connection-string repoint + smoke 8 hosts, (6) backup pipeline integration (mssql_dump_full daily + mssql_tx_log_backup hourly → достигает RPO 1ч), (7) source decommission после 48ч uptime. **Pre-cutover benchmark обязателен** (WAN 10-30ms vs localhost). После first VDS backup-pipeline run — списать [cms-stopgap-backup-daily]. Spawn'd by [mssql-minio-migration-to-vds] decomposition 2026-05-22.
|
||||
**Branch:** n/a
|
||||
**Executed steps:**
|
||||
1. `BACKUP DATABASE WITH COMPRESSION, COPY_ONLY, INIT` на source для 5 DBs (3.17 sec на 235 MB MoreThenCms, total 486 MB)
|
||||
2. `docker cp` → `scp` → `/opt/stacks/databases/mssql/backups/` on VDS (chown 10001:0)
|
||||
3. Traefik static config: добавлен `mssql` entrypoint :1433. **Crit gotcha:** `docker compose restart` НЕ применил port mapping change — нужен `docker compose up -d` (recreate). Симптом: port 1433 не listened.
|
||||
4. ufw allow 1433/tcp
|
||||
5. `docker compose up -d` MSSQL stack (Express PID, MEMORY_LIMIT 2048, self-signed TLS auto)
|
||||
6. `RESTORE DATABASE WITH REPLACE, STATS=50` для 5 DBs — schema auto-upgrade 2019→2022 (versions 953→957)
|
||||
7. `DBCC CHECKDB ... WITH NO_INFOMSGS, PHYSICAL_ONLY` — clean
|
||||
8. **Crit fix:** server-level login `snolla` НЕ восстановился из .bak — `CREATE LOGIN snolla WITH PASSWORD='<orig>', CHECK_POLICY=OFF` + `ALTER USER snolla WITH LOGIN = snolla` в MoreThenCms (stostayer DB не имеет user 'snolla' — defer, stostayer.old site local-only).
|
||||
9. Edit `C:\sites\snolla\Web.config`: `Data Source=localhost` → `Data Source=mssql.kzntsv.site,1433;...;TrustServerCertificate=True`. Backup в `.bak-pre-vds-cutover-20260522`.
|
||||
10. IIS auto-recycle on web.config touch. **Smoke 8 hosts 200 OK ✓** (emspb/snolla.com→on.snolla/pilorama98/labtools.ru+pro/tandemmebel/kupimknigi).
|
||||
|
||||
**Findings закреплены в** [`mssql-on-vds`](../.wiki/concepts/mssql-on-vds.md) §Gotchas: (1) logins-vs-users orphan dance, (2) traefik recreate-not-restart для port mapping, (3) PowerShell не запускает `pass` bash-script → NULL pw + misleading "Login failed", (4) password generator excludeать `+/=` Base64 chars, (5) mssql uid 10001 ownership.
|
||||
|
||||
**Open follow-ups:**
|
||||
- Backup pipeline integration (mssql_dump_full daily + mssql_tx_log_backup hourly → RPO 1ч) — отдельная chore-task после первого backup green.
|
||||
- stostayer.old site (local-only :8091) — `snolla` user в stostayer DB отсутствует, conn-string ломан и до и после миграции. Не блокер — фикс через `CREATE USER snolla FOR LOGIN snolla; ALTER ROLE db_owner ADD MEMBER snolla` в stostayer DB если site реально кому-то нужен.
|
||||
- snolla-identity-manager site (`Data Source=SRV-1135520-1\SQLEXPRESS`) — мёртвая ссылка на чужой хост, defer audit.
|
||||
- 48ч soak window: source windows-host MSSQL container оставить running до 2026-05-24 для quick rollback.
|
||||
|
||||
**Atomic revert:** `Copy-Item C:\sites\snolla\Web.config.bak-pre-vds-cutover-20260522 C:\sites\snolla\Web.config -Force` → IIS auto-recycle.
|
||||
**Branch:** master
|
||||
|
||||
---
|
||||
|
||||
## ⚪ [minio-imgproxy-vds-migration] — Перенести MinIO + imgproxy + imgproxy-nginx с windows-recovery-host на vds-kzntsv. Заодно **upgrade MinIO** `RELEASE.2020-07-13` (5 лет, CVE) → `minio/minio:latest`. `minio.vds.kzntsv.site` + `minio-console.vds.kzntsv.site` через traefik HTTPS.
|
||||
## 🟡 [minio-imgproxy-vds-migration] — Data layer DONE 2026-05-22 (3 GiB / 19324 obj mirrored, upgrade 2020→2025 ✓). **DNS swap `imgproxy.kzntsv.site` → VDS IP pending** (user action).
|
||||
|
||||
Method: snapshot bind-mount source (rollback insurance) → empty new MinIO на VDS → `mc mirror old→new` → fallback `aws s3 sync` если format-compat ломается → repoint CMS endpoints + imgproxy через internal `shared-dbs` network (`http://minio:9000`).
|
||||
**Where I stopped:** Stack live на VDS (`minio.vds.kzntsv.site` + `minio-console.vds.kzntsv.site` + `imgproxy.vds.kzntsv.site` traefik routes ✓). Все buckets mirrored с format compat 2020→2025 verified (mc mirror through S3 API, не сырое filesystem). CMS image URLs пока рендерятся через windows-host imgproxy (DNS `imgproxy.kzntsv.site` всё ещё на windows IP).
|
||||
|
||||
**Status:** ready
|
||||
**Where I stopped:** (not started)
|
||||
**Next action:** См. `minio-imgproxy-vds-migration.md` — full acceptance (9 items) + risks + open questions. Sub-phases: (1) snapshot source bind-mount, (2) deploy stack на VDS (minio + imgproxy + imgproxy-nginx, networks proxy+shared-dbs), (3) traefik HTTPS routes + LE certs + DNS A-records, (4) `mc mirror` per-bucket with verify, (5) repoint CMS image endpoints + smoke 8 sites, (6) backup pipeline integration (minio_mirror daily — recommend rsync over mc mirror для simplicity), (7) source decommission после 48ч. **Open compat risk:** xl.meta format gap 5 лет — dry-run `mc mirror --dry-run` сначала, fallback plan B (same old image на VDS, upgrade later). Spawn'd by [mssql-minio-migration-to-vds] decomposition 2026-05-22.
|
||||
**Branch:** n/a
|
||||
**Executed steps:**
|
||||
1. `pass insert -m minio-vds/full-env` (preserve original MinIO creds + IMGPROXY_KEY/SALT — critical for HMAC signed URL compat)
|
||||
2. VDS: `/opt/stacks/storage/minio-imgproxy/` + scp nginx.conf + write .env from pass + compose (3 services in `proxy` network)
|
||||
3. `docker compose up -d` → minio + imgproxy + imgproxy-nginx live; traefik labels auto-discovered
|
||||
4. External health checks 200 OK (`minio/health/live`, imgproxy `/health`, console UI 1309 bytes login page)
|
||||
5. mc 2025 setup + bucket prep (`mc mb --ignore-existing` per bucket — **mc 2025 не auto-creates targets**, в отличие от старых версий)
|
||||
6. `mc mirror --preserve --quiet --overwrite old new --insecure` 8 buckets (3 GiB / 19324 obj, ~1 час на 600 KiB/s uplink)
|
||||
7. Verify per-bucket — **3.0 GiB / 19324 obj match on both sides ✓**
|
||||
8. **Crit finding:** один файл `Albrecht Dürer ...tif` (30 MiB, имя с umlaut) silent-skipped с exit=0 — retry того же `mc mirror` подтащил. Verify по count+size обязателен, не доверять exit code.
|
||||
|
||||
**Findings закреплены в** [`minio-imgproxy-on-vds`](../.wiki/concepts/minio-imgproxy-on-vds.md) §Gotchas: (1) MinIO upgrade 5y gap works via mc mirror (S3 API), не bind-swap (xl.meta format), (2) mc 2025 НЕ auto-creates buckets, (3) silent skip non-ASCII filename + slow uplink → verify по count, (4) IMGPROXY_KEY/SALT preserve обязательно (HMAC signed URLs), (5) MINIO_ROOT_USER/PASSWORD replace deprecated MINIO_ACCESS_KEY/SECRET — reuse same values.
|
||||
|
||||
**Next action для completion:**
|
||||
1. User: REGRU DNS A-record `imgproxy.kzntsv.site` → 89.253.255.94 (TTL 300s)
|
||||
2. После propagate: добавить router rule `imgproxy.kzntsv.site` в `/opt/stacks/storage/minio-imgproxy/docker-compose.yml` (label imgproxy-nginx сервиса) + `docker compose up -d`
|
||||
3. LE cert auto-issued
|
||||
4. Smoke: открыть любую CMS-страницу с картинками → должна рендерится через VDS imgproxy
|
||||
5. 48ч soak → decommission windows-host containers
|
||||
|
||||
**Backup pipeline TODO:** `minio_mirror` daily в `/opt/stacks/backup/scripts/run.sh` — rsync `/opt/stacks/storage/minio-imgproxy/data` → kreknin.
|
||||
|
||||
**Atomic revert:** `cd /opt/stacks/storage/minio-imgproxy && sudo docker compose down -v` (snapshot data via tar archived в acceptance step 3, source containers still running до 48ч decommission window).
|
||||
**Branch:** master
|
||||
|
||||
---
|
||||
|
||||
## ⚪ [iis-cutover-to-vds-services] — **Финальный cutover** IIS на windows-recovery-host: repoint CMS conn-strings с `localhost,1433` → `mssql.kzntsv.site,1433` + `localhost:9000` → `minio.vds.kzntsv.site`. Это **то ради чего всё затевалось** — миграции MSSQL/MinIO бесполезны без этого шага.
|
||||
## 🟡 [iis-cutover-to-vds-services] — MSSQL cutover DONE 2026-05-22 (8 hosts 200 OK ✓). MinIO image-pipeline cutover ждёт DNS swap `imgproxy.kzntsv.site` (см. `minio-imgproxy-vds-migration`).
|
||||
|
||||
Atomic edit: один `C:\sites\snolla\web.config` обслуживает 11 CMS-хостов через traefik catch-all (`*:8089`) + `stostayer.old\web.config` (local-only). `iisreset` → 11 хостов мигрируют разом. Rollback = revert backup.
|
||||
**MSSQL phase complete:**
|
||||
- Audit: `C:\sites\snolla\Web.config` обслуживает 11 CMS hosts (snolla catch-all `*:8089`). Только 1 conn-string на MoreThenCms DB, login `snolla` (не sa).
|
||||
- `stostayer.old\web.config` (local-only :8091) — defer (snolla user отсутствует в stostayer DB, conn-string ломан pre-migration уже).
|
||||
- `stostayer\web.config` уже на external `www.stostayer.ru,1433` — не наш scope (внешний MSSQL).
|
||||
- `snolla-identity-manager\web.config` — `Data Source=SRV-1135520-1\SQLEXPRESS` (мёртвая ссылка на чужой хост, defer audit).
|
||||
- Edit `Data Source=localhost` → `mssql.kzntsv.site,1433;TrustServerCertificate=True` + backup `.bak-pre-vds-cutover-20260522`
|
||||
- IIS auto-recycle на web.config touch (без iisreset).
|
||||
- Smoke 8 priority hosts: emspb/snolla.com→on.snolla/pilorama98/labtools.ru/labtools.pro/www.tandemmebel/kupimknigi — **все 200 OK**, latency 0.3-3.1s (tandemmebel самый медленный — большая страница).
|
||||
|
||||
**Status:** blocked (waiting on `mssql-vds-migration` + `minio-imgproxy-vds-migration`)
|
||||
**Where I stopped:** (not started)
|
||||
**Next action:** См. `iis-cutover-to-vds-services.md` — full acceptance (11 items). Sub-phases: (1) audit config locations (`Get-ChildItem -Recurse C:\sites -Include web.config,appsettings.*.json | Select-String 'localhost,1433|localhost:9000'`) → mapping site→DB→endpoint, (2) pre-cutover benchmark (admin/assets/getList + search + каталоги) → baseline, (3) backup web.config'ов, (4) edit conn-strings (`localhost,1433` → `mssql.kzntsv.site,1433;TrustServerCertificate=true`), (5) edit MinIO/imgproxy endpoints (audit-driven), (6) iisreset + smoke 8 hosts, (7) post-cutover benchmark <2x degradation gate, (8) MinIO write smoke (admin upload → mc ls verify + imgproxy render), (9) 48ч soak, (10) decommission source containers + списать `cms-stopgap-backup-daily`. **Open risk:** если MinIO/imgproxy URLs hardcoded в скомпилированных DLL — fallback: оставить `imgproxy-nginx` на windows-host, transparent proxy на VDS MinIO. Spawn'd by user-poke 2026-05-22 («IIS перенастроить!»).
|
||||
**Blocker:** mssql-vds-migration + minio-imgproxy-vds-migration
|
||||
**Branch:** n/a
|
||||
**MinIO image-pipeline phase (ждёт DNS swap):**
|
||||
- В `web.config`'ах **нет** прямых refs `localhost:9000` / `localhost:8788` (URLs идут через `imgproxy.kzntsv.site` domain, не localhost).
|
||||
- → Cutover image rendering = DNS A-record swap `imgproxy.kzntsv.site` → 89.253.255.94 (user action, см. [[minio-imgproxy-vds-migration]] Next action).
|
||||
- Никакого web.config edit для MinIO/imgproxy не требуется — IMGPROXY_KEY/SALT preserved → existing CMS image URLs валидны на новом stack'е.
|
||||
|
||||
**48ч soak:** monitor через ntfy `vds-ops` + manual smoke 24h/48h marks. Source windows-host MSSQL container оставить running до 2026-05-24 для rollback.
|
||||
|
||||
**Decommission window (после 48ч green):**
|
||||
1. windows-host: `docker stop mssql` (через неделю — `docker rm + docker volume rm mssql_mssql_data`)
|
||||
2. После DNS swap MinIO: `docker stop minio imgproxy imgproxy-nginx`
|
||||
3. Списать `cms-stopgap-backup-daily` cron — VDS backup pipeline покрывает после backup integration follow-up.
|
||||
|
||||
**Atomic revert (full):**
|
||||
```powershell
|
||||
Copy-Item C:\sites\snolla\Web.config.bak-pre-vds-cutover-20260522 C:\sites\snolla\Web.config -Force
|
||||
# IIS auto-recycle (или iisreset /restart)
|
||||
# Убедиться windows-host MSSQL container running (если decommissioned — docker start mssql)
|
||||
```
|
||||
**Status:** in_progress (MSSQL ✓, MinIO DNS swap pending)
|
||||
**Branch:** master
|
||||
|
||||
---
|
||||
|
||||
|
||||
98
.wiki/concepts/minio-imgproxy-on-vds.md
Normal file
98
.wiki/concepts/minio-imgproxy-on-vds.md
Normal file
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: MinIO + imgproxy stack on vds-kzntsv
|
||||
status: live (data-layer); DNS swap pending для imgproxy.kzntsv.site
|
||||
tags: [vds, minio, imgproxy, migration, ops]
|
||||
related: [[vds-kzntsv]], [[recovery-architecture-snapshot]], [[mssql-on-vds]]
|
||||
---
|
||||
|
||||
# MinIO + imgproxy on vds-kzntsv
|
||||
|
||||
Запущен 2026-05-22 как часть `minio-imgproxy-vds-migration`. Заодно **upgrade MinIO** `RELEASE.2020-07-13` (5 лет, CVE-куча) → `RELEASE.2025-09-07`.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
CMS templates (URL pattern: imgproxy.kzntsv.site/<sig>/.../plain/s3://<bucket>/<path>)
|
||||
→ traefik (windows-host) [пока, до DNS swap]
|
||||
→ imgproxy-nginx (windows-host) [пока]
|
||||
→ imgproxy (windows-host) [пока]
|
||||
→ MinIO localhost:9000 (windows-host) [пока]
|
||||
|
||||
После DNS swap imgproxy.kzntsv.site → 89.253.255.94 (VDS):
|
||||
→ VDS traefik (HTTPS, LE cert)
|
||||
→ imgproxy-nginx (VDS, nginx:alpine, 10 GB cache)
|
||||
→ imgproxy (VDS, darthsim/imgproxy:latest)
|
||||
→ minio (VDS, RELEASE.2025-09-07, internal docker DNS через proxy network)
|
||||
```
|
||||
|
||||
Stack: `/opt/stacks/storage/minio-imgproxy/{docker-compose.yml,.env,data,nginx.conf,nginx-cache}`. Все 3 контейнера в `proxy` network — service-name DNS работает.
|
||||
|
||||
**Traefik routes (live):**
|
||||
- `minio.vds.kzntsv.site` → minio:9000 (S3 API)
|
||||
- `minio-console.vds.kzntsv.site` → minio:9001 (web UI)
|
||||
- `imgproxy.vds.kzntsv.site` → imgproxy-nginx:80 (test endpoint pre-cutover)
|
||||
|
||||
После DNS swap имя `imgproxy.kzntsv.site` (без `.vds.`) добавить в traefik label imgproxy-nginx сервиса.
|
||||
|
||||
## Migration recipe
|
||||
|
||||
```bash
|
||||
# 1. pass insert (local) — preserve original IMGPROXY_KEY/SALT, reuse MinIO creds
|
||||
pass insert -m minio-vds/full-env <<EOF
|
||||
MINIO_ROOT_USER=<same-as-source>
|
||||
MINIO_ROOT_PASSWORD=<same-as-source>
|
||||
IMGPROXY_KEY=<same-as-source-128hex>
|
||||
IMGPROXY_SALT=<same-as-source-128hex>
|
||||
EOF
|
||||
|
||||
# 2. VDS: create dir + scp nginx.conf + write .env from pass + write compose
|
||||
ssh vitya@vds 'sudo mkdir -p /opt/stacks/storage/minio-imgproxy/{data,nginx-cache}
|
||||
sudo chown -R vitya:vitya /opt/stacks/storage'
|
||||
scp <source>/nginx.conf vitya@vds:/opt/stacks/storage/minio-imgproxy/
|
||||
pass show minio-vds/full-env | ssh vitya@vds 'cat > /opt/stacks/storage/minio-imgproxy/.env
|
||||
chmod 600 .env'
|
||||
|
||||
# 3. docker compose up -d (image pull + start all 3)
|
||||
|
||||
# 4. Local mc setup + bucket prep
|
||||
mc alias set old http://localhost:9000 <creds>
|
||||
mc alias set new https://minio.vds.kzntsv.site <creds> --insecure
|
||||
for b in $(mc ls old | awk '{print $NF}' | tr -d /); do
|
||||
mc mb --ignore-existing new/$b --insecure # mc 2025 не auto-creates на mirror
|
||||
done
|
||||
|
||||
# 5. Mirror (background, ~1 час на 3 GB при 600 KiB/s)
|
||||
mc mirror --preserve --quiet --overwrite old new --insecure
|
||||
|
||||
# 6. Verify per-bucket (size + object count)
|
||||
for b in $(mc ls old | awk '{print $NF}' | tr -d /); do
|
||||
echo "[$b]"; mc du old/$b; mc du new/$b --insecure
|
||||
done
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
|
||||
1. **MinIO upgrade 5-летний gap WORKS via mc mirror** — старый FS backend (2020) → новый erasure-coded single-drive (2025) совместим через S3 API copy. `mc mirror` reads через S3 API, не сырое filesystem. Бинарный bind-mount свопнуть НЕЛЬЗЯ — формат `xl.meta` разный, новый MinIO не поднимется на старых dirs.
|
||||
2. **mc 2025 НЕ auto-creates target buckets** — old mc (<2023?) делало неявно. Симптом: `Failed to perform mirroring The specified bucket does not exist`. Fix: `mc mb --ignore-existing new/<b>` для каждого bucket заранее.
|
||||
3. **Non-ASCII filenames + slow uplink → partial mirror failure**: один файл `Albrecht Dürer ...tif` (30 MiB) в `imgproxytest` bucket не доехал с первого `mc mirror` exit=0 — silent skip без error. Retry того же `mc mirror` подтащил. Recommendation: всегда verify по object count + size после mirror, не doверять exit code.
|
||||
4. **IMGPROXY_KEY + IMGPROXY_SALT preserve обязательно** — это HMAC signing для URLs. Если поменять, все pre-existing CMS image URLs (signed ссылки в шаблонах + кешированные в admin) ломаются. Reuse same values из source.
|
||||
5. **MinIO root creds vs AWS-style**: source использует MINIO_ACCESS_KEY/MINIO_SECRET_KEY (deprecated env vars), новый MinIO — MINIO_ROOT_USER/MINIO_ROOT_PASSWORD. Reuse same values (no rotation в этой миграции) → CMS+imgproxy credentials не меняются. Rotation — отдельная hardening-таска.
|
||||
|
||||
## DNS swap (pending — user action)
|
||||
|
||||
`imgproxy.kzntsv.site` сейчас A-record на windows-host IP. Чтобы переключить картинки на VDS:
|
||||
1. REGRU: `imgproxy.kzntsv.site` A → 89.253.255.94 (TTL 300s).
|
||||
2. Дождаться propagate (`Resolve-DnsName imgproxy.kzntsv.site`).
|
||||
3. В `/opt/stacks/storage/minio-imgproxy/docker-compose.yml` для service `imgproxy-nginx` добавить router rule `imgproxy.kzntsv.site` рядом с existing `imgproxy.vds.kzntsv.site`.
|
||||
4. `docker compose up -d` (apply labels).
|
||||
5. LE cert auto-issued.
|
||||
|
||||
## Rollback
|
||||
|
||||
```bash
|
||||
# On VDS
|
||||
cd /opt/stacks/storage/minio-imgproxy && sudo docker compose down -v
|
||||
# Source windows-host MinIO + imgproxy + imgproxy-nginx должны быть still running (48ч uptime acceptance).
|
||||
# Если уже decommissioned — docker start minio imgproxy imgproxy-nginx.
|
||||
# Snapshot insurance: tar archive bind-mount source data preserved отдельно (acceptance step 3).
|
||||
```
|
||||
99
.wiki/concepts/mssql-on-vds.md
Normal file
99
.wiki/concepts/mssql-on-vds.md
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: MSSQL on vds-kzntsv (Express 2022 Linux)
|
||||
status: live
|
||||
tags: [vds, mssql, migration, ops]
|
||||
related: [[vds-kzntsv]], [[recovery-architecture-snapshot]], [[traefik-tcp-passthrough-vs-starttls]], [[db-tls-self-signed-via-traefik-raw-tcp]]
|
||||
---
|
||||
|
||||
# MSSQL on vds-kzntsv
|
||||
|
||||
Запущен 2026-05-22 как часть `mssql-vds-migration`. SPOF с windows-recovery-host снят для CMS DB park.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
IIS snolla site (web.config)
|
||||
→ mssql.kzntsv.site:1433 (LE/DNS A → 89.253.255.94)
|
||||
→ VDS traefik :1433 (TCP entrypoint, HostSNI(*))
|
||||
→ mssql container :1433 (self-signed TLS terminated по TDS)
|
||||
→ /var/opt/mssql/data/{5 prod DBs}
|
||||
```
|
||||
|
||||
Stack: `/opt/stacks/databases/mssql/{docker-compose.yml,.env,data,backups}`. Networks `proxy` only.
|
||||
|
||||
**Image:** `mcr.microsoft.com/mssql/server:2022-latest` (RTM-CU25, build 16.0.4255.1, on Ubuntu 22.04.5 LTS).
|
||||
**Edition:** Express (`MSSQL_PID=Express`) — production licensing OK, 10 GB/DB cap (max .mdf сейчас `stostayer` 968 MB → 10× запас).
|
||||
**Memory:** `MSSQL_MEMORY_LIMIT_MB=2048` env (Express auto-caps на 1410 в любом случае).
|
||||
**TLS:** self-signed cert, mssql generates automatically. Client connects with `TrustServerCertificate=True`. Traefik forwards raw TCP — TLS terminates at mssql.
|
||||
|
||||
## Migration recipe (one-shot, executed 2026-05-22)
|
||||
|
||||
Источник: `mcr.microsoft.com/mssql/server:2019-latest` Developer на windows-recovery-host (volume `mssql_mssql_data` 26.6 GB; real data ~2.4 GB; .ldf logs 12 GB inflated).
|
||||
|
||||
```sql
|
||||
-- 1. Source: BACKUP DATABASE for each prod DB (5 total)
|
||||
BACKUP DATABASE [<db>] TO DISK='/var/opt/mssql/backups/<db>.bak'
|
||||
WITH COMPRESSION, COPY_ONLY, INIT, STATS=50;
|
||||
-- Compressed total: 486 MB (10× от .mdf size — built-in compression на UTF-16/varchar pads)
|
||||
```
|
||||
|
||||
```bash
|
||||
# 2. Extract from container → scp → VDS bind
|
||||
docker cp mssql:/var/opt/mssql/backups/. C:/tmp/mssql-backups/
|
||||
scp C:/tmp/mssql-backups/*.bak vitya@vds.kzntsv.site:/tmp/mssql-bak-staging/
|
||||
ssh vitya@vds.kzntsv.site 'sudo mv /tmp/mssql-bak-staging/*.bak /opt/stacks/databases/mssql/backups/
|
||||
sudo chown 10001:0 /opt/stacks/databases/mssql/backups/*.bak'
|
||||
```
|
||||
|
||||
```yaml
|
||||
# 3. compose + .env (см. /opt/stacks/databases/mssql/)
|
||||
# MSSQL_SA_PASSWORD из pass show mssql-vds/sa-password (32-char alnum, no special chars)
|
||||
```
|
||||
|
||||
```yaml
|
||||
# 4. Traefik: добавить TCP entrypoint в /opt/stacks/traefik/data/traefik.yml
|
||||
entryPoints:
|
||||
mssql:
|
||||
address: ":1433"
|
||||
# + port 1433 в /opt/stacks/traefik/docker-compose.yml ports list
|
||||
# + ufw allow 1433/tcp
|
||||
# + sudo docker compose up -d (RECREATE, не restart — port mapping)
|
||||
```
|
||||
|
||||
```sql
|
||||
-- 5. RESTORE per DB
|
||||
RESTORE DATABASE [<db>] FROM DISK='/var/opt/mssql/backups/<db>.bak' WITH REPLACE, STATS=50;
|
||||
-- 2019 → 2022 schema upgrade автоматический (versions 953→957). DBCC CHECKDB PHYSICAL_ONLY clean.
|
||||
```
|
||||
|
||||
```sql
|
||||
-- 6. CRITICAL: server-level logins НЕ переезжают в .bak (sysadmin/master DB only).
|
||||
-- Создать manually + fix orphan users в каждой DB:
|
||||
CREATE LOGIN snolla WITH PASSWORD = '<from-source-web.config>', CHECK_POLICY = OFF;
|
||||
USE MoreThenCms;
|
||||
ALTER USER snolla WITH LOGIN = snolla;
|
||||
-- Repeat for каждой DB где web.config упоминает данного user'а.
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
|
||||
1. **Logins vs users**: .bak восстанавливает DB-level users (с их role memberships + permissions), но НЕ server logins. Sites с `User Id=X` в conn-string ловят `Login failed for user 'X'` после restore, пока не выполнить `CREATE LOGIN` + `ALTER USER ... WITH LOGIN`.
|
||||
2. **Traefik recreate, не restart**: добавление port mapping в `docker-compose.yml` требует **recreate** контейнера (`docker compose up -d`), не `restart`. `restart` оставит старые published ports.
|
||||
3. **PowerShell + `pass` (bash script)**: `pass show` в PowerShell возвращает NULL (PS не запускает bash-скрипты напрямую). Нужно `bash -c "pass show ..."` или literal. Симптом: `Login failed for user 'sa'` несмотря на правильный пароль на VDS.
|
||||
4. **`MSSQL_SA_PASSWORD` спец-символы**: rotation password generator должен excludeавать `+/=` (Base64) и shell-meta (`$`, `` ` ``, `"`, `'`, `\`). Иначе env-var passing через ssh heredoc или sed конструкторы ломаются. Пример безопасного: `[Convert]::ToBase64String($bytes) -replace '[+/=]','x'`.
|
||||
5. **MSSQL Linux user uid**: `mssql` user = uid 10001. Bind-mount должен быть `chown 10001:0` чтобы контейнер read/write. Parent dir owns `vitya:vitya` чтобы можно было редактировать compose без sudo.
|
||||
|
||||
## Backup integration (TODO)
|
||||
|
||||
Расширить `/opt/stacks/backup/scripts/run.sh` (см. [[vds-backup-rsync-kreknin]]):
|
||||
- `mssql_dump_full` daily — `BACKUP DATABASE [<db>] TO DISK='...' WITH COMPRESSION, COPY_ONLY` через `docker exec mssql sqlcmd ...`
|
||||
- `mssql_tx_log_backup` hourly — `BACKUP LOG [<db>] TO DISK='...'` для FULL-recovery DBs (только `MoreThenCms` — остальные SIMPLE).
|
||||
- Достигает target RPO 1ч (vs current daily snapshot).
|
||||
- ntfy push на `vds-backup` topic.
|
||||
|
||||
## Rollback recipe
|
||||
|
||||
1. Revert IIS web.config'ы (см. `.bak-pre-vds-cutover-20260522` файлы).
|
||||
2. `iisreset /restart` (или ждать auto-recycle ~30 sec).
|
||||
3. Убедиться windows-host MSSQL контейнер всё ещё running (acceptance 48ч uptime до decommission).
|
||||
4. Если уже decommissioned: `docker start mssql` (volume сохранён ещё неделю по acceptance).
|
||||
@@ -24,7 +24,9 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
- [future-resilient-architecture-goals](concepts/future-resilient-architecture-goals.md) — fault-tolerance roadmap placeholder (расширяется через `[resilience-roadmap-design]`)
|
||||
- [hyper-backup-structure-and-recovery](concepts/hyper-backup-structure-and-recovery.md) — Hyper Backup — структура репо и стратегия восстановления
|
||||
- [iis-migration-2026-05-19-postmortem](concepts/iis-migration-2026-05-19-postmortem.md) — post-mortem миграции CMS на нативный IIS, 2026-05-19
|
||||
- [minio-imgproxy-on-vds](concepts/minio-imgproxy-on-vds.md) — MinIO+imgproxy stack на VDS, миграция с upgrade 2020→2025 + DNS swap pending
|
||||
- [mssql-container-data-restore](concepts/mssql-container-data-restore.md) — MSSQL контейнер с восстановленными production data — паттерн
|
||||
- [mssql-on-vds](concepts/mssql-on-vds.md) — MSSQL Express 2022 Linux на VDS — миграция + login orphan fix + traefik TCP gotchas
|
||||
- [ocis-on-vds-deploy-recipe](concepts/ocis-on-vds-deploy-recipe.md) — oCIS на VDS — deploy recipe + non-obvious gotchas (UID 1001 vs 1000, basic auth, LibreGraph user-create)
|
||||
- [portainer-2.21-admin-password-regression](concepts/portainer-2.21-admin-password-regression.md) — Portainer 2.21 `--admin-password` regression + min 12-char policy
|
||||
- [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2)
|
||||
|
||||
Reference in New Issue
Block a user