feat(on-snolla): v3 cutover LIVE — snolla 0.43.2 (aws-sdk v2→v3) + runbook migration

v3 pilot on.snolla.com end-goal (user 2026-07-30): bump @snollajs/snolla
0.42.1→0.43.2 + @smithy resolutions (root package.json, on.snolla.com eb8c143).
Portainer PUT stack 22 → registry.kzntsv.site/on-snolla:eb8c143, env-preserving
8/8, mem_limit 512m. Live smoke GREEN: theme asset 200 97324 B (v3 aws-sdk v3
S3-direct read из vds MinIO 2025), sitemap+sub-sitemaps byte-identical, /c 404.
Rollback = 07db7e3 (v2, жив).

runbook migration (дисциплина): scripts/minio-split-cutover/runbook.md →
.wiki/concepts/minio-split-cutover-runbook.md (конвенция: runbook'и в .wiki/concepts/).
Creds normalized → pass show minio-vds/full-env (wiki-конвенция, не plaintext).
+ index.md, log.md, on-snolla-vds-deploy-runbook v3-секция.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-30 14:30:38 +03:00
parent afb6e5f0d6
commit f56eb2f800
6 changed files with 95 additions and 17 deletions

View File

@@ -24,7 +24,7 @@ prev_session_id: 2026-07-24-stostayer-markdown-render-fix
- **Live-smoke** `https://on.snolla.com`: theme asset 200 97324 B, `/`,`/robots`,`/sitemap`,`/yandex` 200, `/c` 404 parity. - **Live-smoke** `https://on.snolla.com`: theme asset 200 97324 B, `/`,`/robots`,`/sitemap`,`/yandex` 200, `/c` 404 parity.
TLS cert не тронут (LE YR1, CN=on.snolla.com, до Oct 18). Логи: `Server Listening`, aws-sdk v2 EOL warning (ожидаемо), нет крашей. TLS cert не тронут (LE YR1, CN=on.snolla.com, до Oct 18). Логи: `Server Listening`, aws-sdk v2 EOL warning (ожидаемо), нет крашей.
- **Закрытие:** compose source-of-truth `host-stacks/vds-kzntsv/on-snolla.compose.yml` обновлён (тег 07db7e3 + endpoint + rollback-коммент); - **Закрытие:** compose source-of-truth `host-stacks/vds-kzntsv/on-snolla.compose.yml` обновлён (тег 07db7e3 + endpoint + rollback-коммент);
`scripts/minio-split-cutover/runbook.md` (новый) — Track B progress-таблица; commit `443713e8`. `.wiki/concepts/minio-split-cutover-runbook.md` (перенесён из scripts/) — Track B progress-таблица; commit `443713e8`.
- **Memory:** NEW `aws-sdk-v2-minio-2025-works-no-smithy-pin.md`@smithy SigV4 regression = v3-only, v2 идёт без пина. - **Memory:** NEW `aws-sdk-v2-minio-2025-works-no-smithy-pin.md`@smithy SigV4 regression = v3-only, v2 идёт без пина.
### План отката ### План отката
@@ -39,7 +39,7 @@ RUVDS DECOMM 2026-07-21 — rollback только образ-тегом.
## Open треки ## Open треки
| Трек | Готовность | Entry-point | | Трек | Готовность | Entry-point |
|---|---|---| |---|---|---|
| **MinIO split B3 — остальные 5 сайтов** | ⏳ TODO — пилот on-snolla GREEN, паттерн отработан | `scripts/minio-split-cutover/runbook.md` §B3 + progress-таблица | | **MinIO split B3 — остальные 5 сайтов** | ⏳ TODO — пилот on-snolla GREEN, паттерн отработан | `.wiki/concepts/minio-split-cutover-runbook.md` §B3 + progress-таблица |
| MinIO split Track A (books-vds minio 2020→2025) | ⏳ TODO — transparent, отдельно | runbook.md §Track A | | MinIO split Track A (books-vds minio 2020→2025) | ⏳ TODO — transparent, отдельно | runbook.md §Track A |
| MinIO split B4 .NET catch-all админ s3 endpoint | ⏳ TODO — `C:\sites\snolla\Web.config` serviceURL → minio.vds.kzntsv.site | runbook.md §B4 | | MinIO split B4 .NET catch-all админ s3 endpoint | ⏳ TODO — `C:\sites\snolla\Web.config` serviceURL → minio.vds.kzntsv.site | runbook.md §B4 |
| MinIO split B5 Obsidian Remotely Save endpoint | ⏳ TODO — obsidian бакет смиррорен (B1), можно менять endpoint | runbook.md §B5; memory `obsidian-remotely-save-endpoint-after-mirror` | | MinIO split B5 Obsidian Remotely Save endpoint | ⏳ TODO — obsidian бакет смиррорен (B1), можно менять endpoint | runbook.md §B5; memory `obsidian-remotely-save-endpoint-after-mirror` |

View File

@@ -1,7 +1,15 @@
---
title: MinIO split — cutover runbook (Track A books-vds 2020→2025 + Track B CMS-media → vds)
type: concept
tags: [minio, vds, books-vds, cutover, runbook, migration, snolla, s3, imgproxy, obsidian]
related: [[../entities/vds-kzntsv], [../entities/books-vds], [on-snolla-vds-deploy-runbook], [tandemmebel-vds-deploy-runbook], [snolla-live-prod-inplace-image-bump], [minio-imgproxy-on-vds], [portainer-stack-management-vds]]
updated: 2026-07-30
---
# MinIO split — cutover runbook # MinIO split — cutover runbook
> **Режим:** подготовка. **На железе — НИЧЕГО без команды user.** Все команды готовы к выполнению по «го». > **Режим:** подготовка. **На железе — НИЧЕГО без команды user.** Все команды готовы к выполнению по «го».
> Owner: admin. Создано 2026-07-29. > Owner: admin. Создано 2026-07-29. Перенесён из `scripts/minio-split-cutover/` 2026-07-30 (дисциплина: runbook'и → `.wiki/concepts/`).
## Goal ## Goal
@@ -9,12 +17,12 @@
- **books-vds shared `minio`** (`minio.kzntsv.site`) → только slovo-бакеты books-приложений. Апгрейд 2020→2025. - **books-vds shared `minio`** (`minio.kzntsv.site`) → только slovo-бакеты books-приложений. Апгрейд 2020→2025.
- **books-vds `bookva-minio`** → bookva-бакеты (уже там с 2026-05). Апгрейд 2020→2025. Консоль наружу НЕ выставляем. - **books-vds `bookva-minio`** → bookva-бакеты (уже там с 2026-05). Апгрейд 2020→2025. Консоль наружу НЕ выставляем.
- **vds `minio`** (`minio.vds.kzntsv.site`, уже 2025-09-07) → CMS-медиа snolla-сайтов + artmone + obsidian + modules + modulair + maxmind + strapi. - **vds `minio`** (`minio.vds.kzntsv.site`, уже 2025-09-07) → CMS-медиа snolla-сайтов + artmone + obsidian + modules + modulair + maxmind + strapi.
- Креды **не трогаем** (один root-ключ `AKIAJ2YJP72W6ZHCRE6Q` на все инстансы). - Креды **не трогаем** (один root-ключ на все инстансы; **доступ → `pass show minio-vds/full-env`**, поля `MINIO_ROOT_USER`/`MINIO_ROOT_PASSWORD`). Креды НЕ в git.
## Два независимых трека ## Два независимых трека
- **Track A — апгрейд books-vds minio (shared + bookva).** Не требует правок apps (transparent: hostname/creds/контент сохраняются). Можно делать отдельно, до/после Track B. - **Track A — апгрейд books-vds minio (shared + bookva).** Не требует правок apps (transparent: hostname/creds/контент сохраняются). Можно делать отдельно, до/после Track B.
- **Track B — сплит CMS-медиа на vds.** Координированный кутовer: миррор → DNS-flip imgproxy → snolla deploy. Требует гейтов. - **Track B — сплит CMS-медиа на vds.** Координированный cutover: миррор → DNS-flip imgproxy → snolla deploy. Требует гейтов.
## Progress (2026-07-30) ## Progress (2026-07-30)
@@ -22,14 +30,70 @@
|---|---|---| |---|---|---|
| B1 миррор CMS-медиа books-vds → vds minio | ✅ DONE | galleries/pilorama98/themes/assets смиррорены (свежим миррором поверх stale 2026-05) | | B1 миррор CMS-медиа books-vds → vds minio | ✅ DONE | galleries/pilorama98/themes/assets смиррорены (свежим миррором поверх stale 2026-05) |
| B2 DNS-flip `imgproxy.kzntsv.site` → 89.253.255.94 | ✅ LIVE | imgproxy.kzntsv.site/<pilorama98-image> → 200 webp (vds imgproxy ← vds minio); CMS-сайты берут картинки через vds | | B2 DNS-flip `imgproxy.kzntsv.site` → 89.253.255.94 | ✅ LIVE | imgproxy.kzntsv.site/<pilorama98-image> → 200 webp (vds imgproxy ← vds minio); CMS-сайты берут картинки через vds |
| **B3 on-snolla пилот (S3-direct-path)** | ✅ LIVE 2026-07-30 | in-place bump стека 22 `473923e494db→07db7e3` (snolla 0.42.1 v2, config endpoint → minio.vds.kzntsv.site, без бампа package.json). Theme-assets `/themes/c406…/…` → 200 97324 B == live (aws-sdk v2 → vds minio 2025 — compat подтверждена, главный риск закрыт). Sitemap 3/3 parity, `/c` 404 parity. Rollback-тег `473923e494db` в registry. | | **B3 on-snolla v2-пилот (S3-direct-path)** | ✅ LIVE 2026-07-30 | in-place bump стека 22 `473923e494db→07db7e3` (snolla 0.42.1 v2, config endpoint → minio.vds.kzntsv.site, без бампа package.json). Theme-assets `/themes/c406…/…` → 200 97324 B == live (aws-sdk v2 → vds minio 2025 — compat подтверждена, главный риск закрыт). Sitemap 3/3 parity, `/c` 404 parity. Rollback-тег `473923e494db` в registry. **Промежуточный** шаг — v2 совместим, но v3 — конечная цель (user 2026-07-30). |
| B3 остальные 5 сайтов (kupimknigi/tandemmebel/labtools/labtools.pro/emspb) | ⏳ TODO | тот же паттерн bump config-endpoint; labtools/labtools.pro/emspb — image-bump (уже боевые на vds); tandemmebel BLOCKED (визуальный дефект sharp-staging); kupimknigi — проверить cutover-статус | | **B3v3 on-snolla v3-пилот** | ✅ LIVE 2026-07-30 | `@snollajs/snolla 0.43.2` published (verdaccio latest). Live MinIO verify ЗЕЛЁНЫЙ (snolla, оба конфига). **v3 cutover 2026-07-30T11:28Z**: bump `@snollajs/snolla 0.42.1→0.43.2` + resolutions (root package.json), commit `eb8c143` pushed, build на VDS → `registry.kzntsv.site/on-snolla:eb8c143`, Portainer PUT stack 22 env-preserving (8/8), prune:false pullImage:true, mem_limit 512m. Throwaway staging :5078 parity-gate GREEN (theme asset 200 97324 B byte-identical, sitemapindex+3 sub-sitemaps byte-identical, /c 404 parity). Live smoke GREEN: / 200, robots/sitemap/sub-sitemaps 200, /yandex 200, theme asset 200 97324 B (v3 aws-sdk v3 S3-direct read из vds MinIO 2025). TLS не тронут (LE до Oct 18). Rollback = образ-тег `07db7e3` (v2, жив). |
| B3 остальные 5 сайтов (kupimknigi/tandemmebel/labtools/labtools.pro/emspb) | ⏳ TODO | после v3-пилота on-snolla; тот же паттерн (bump @snollajs/snolla→0.43.2 + **resolutions** + rebuild). tandemmebel BLOCKED (визуальный дефект sharp-staging); kupimknigi — проверить cutover-статус |
| Track A (books-vds minio 2020→2025) | ⏳ TODO | transparent, отдельно от Track B | | Track A (books-vds minio 2020→2025) | ⏳ TODO | transparent, отдельно от Track B |
| B4 .NET catch-all админ s3 endpoint | ⏳ TODO | `C:\sites\snolla\Web.config` serviceURL → minio.vds.kzntsv.site | | B4 .NET catch-all админ s3 endpoint | ⏳ TODO | `C:\sites\snolla\Web.config` serviceURL → minio.vds.kzntsv.site |
| B5 Obsidian Remotely Save endpoint | ⏳ TODO | после B1 миррора obsidian (готово) — менять endpoint | | B5 Obsidian Remotely Save endpoint | ⏳ TODO | после B1 миррора obsidian (готово) — менять endpoint |
**Решение user (2026-07-30):** сплит без бампа snolla-пакетов — сайты остаются на 0.42.1 + aws-sdk v2, только config endpoint. snolla-евый v3-трек (0.43.1/0.7.8/0.17.2) — HOLD, отдельная история (stostayer). Пилот on-snolla подтвердил: **v2 vs MinIO 2025 работает** (без @smithy pin) — SignatureDoesNotMatch нет. **Решение user (2026-07-30):** сплит без бампа snolla-пакетов — сайты остаются на 0.42.1 + aws-sdk v2, только config endpoint. snolla-евый v3-трек (0.43.1/0.7.8/0.17.2) — HOLD, отдельная история (stostayer). Пилот on-snolla подтвердил: **v2 vs MinIO 2025 работает** (без @smithy pin) — SignatureDoesNotMatch нет.
**Разворот 2026-07-30T11:00Z:** v3 — конечная цель (user). v3 опубликована (см. §B3-v3). Промежуточный v2-пилот доказал совместимость; v3-пилот on-snolla — следующий шаг после live MinIO verify.
---
## §B3-v3 — v3-бамп (resolutions = optional determinism, НЕ mandatory)
`@snollajs/snolla 0.43.2` опубликована 2026-07-30 на verdaccio (latest): `@snollajs/liquid 0.11.0` + `@snollajs/data 0.15.0` + `@snollajs/core 0.26.4` (peerDep `@snollajs/data` widen `<0.15.0``<0.16.0`баг-фикс: кап не расширен в `21c73aa`) + `@snollajs/snolla 0.43.2` (@smithy pin + `@aws-sdk/client-s3 3.1005.0` exact baked в deps). Коммит snolla `a8b198d`. Тесты core 259/259, snolla 120/120.
### Live MinIO verify 2026-07-30 — ЗЕЛЁНЫЙ (оба конфига)
snolla гоняла clean-consumer install `@snollajs/snolla@0.43.2` против живого `minio.vds.kzntsv.site`:
- **Run A** (с resolutions, `@smithy/signature-v4` 5.3.11 на signing-path): LIST/READ-PARITY/PUT/GET/MULTIPART — все OK, EXIT 0.
- **Run B** (БЕЗ resolutions, `@smithy/signature-v4` **5.6.12** на signing-path): те же тесты — **все OK, EXIT 0**.
**Оба зелёных.** 5.6.12 НЕ даёт SignatureDoesNotMatch против vds MinIO 2025. Regression-гипотеза (v3 SigV4 vs MinIO) **не воспроизвелась end-to-end** — была halted-bisect гипотезой, зацементированной как «CONFIRMED» без live-теста (косяк коммуникации, исправлен 2026-07-30). См. admin memory `aws-sdk-v3-smithy-sigv4-minio-regression`.
### Resolutions = optional determinism, НЕ SigV4-необходимость
Dual-instance механика реальна (5.3.11 exact из snolla/core + 5.6.12 из `@aws-sdk/core` рядом, без resolutions), но 5.6.12 на signing-path **работает** против vds MinIO 2025. Поэтому:
- `resolutions`-блок в package.json сайта — **опциональный** determinism-hardening (зафиксировать @smithy от свежего re-resolve, version-stability), НЕ обязательный для SigV4.
- Бамп только версии `@snollajs/snolla` без resolutions — **работает** (verify доказал).
- Рекомендую всё же ставить resolutions (детерминизм, безобидно, 5.3.11 тоже зелёный) — но framing «упадёт без resolutions» **ложен**, убрать.
### Copy-paste resolutions-блок (optional, recommended для determinism)
```json
"resolutions": {
"@aws-sdk/client-s3": "3.1005.0",
"@aws-sdk/lib-storage": "3.1005.0",
"@smithy/signature-v4": "5.3.11",
"@smithy/node-http-handler": "4.4.14",
"@smithy/fetch-http-handler": "5.3.13",
"@smithy/protocol-http": "5.3.11",
"@smithy/middleware-endpoint": "4.4.23",
"@smithy/middleware-retry": "4.4.40"
}
```
### v3 bump procedure (per site, после live MinIO verify ⚪)
1. `package.json`: `@snollajs/snolla``0.43.2` + вставить resolutions-блок выше (optional но recommended).
2. `yarn install` (clean resolve — убедиться `npm ls @smithy/signature-v4` == single instance).
3. Build на VDS из site-репо (`deploy/Dockerfile`, build-arg VERDACCIO_TOKEN) → `registry.kzntsv.site/<site>-web:<sha>`.
4. Throwaway staging `:50XX` из env живого контейнера → parity-gate (theme asset 200 97324 B == live, sitemap 3/3, `/c` 404 parity).
5. Portainer PUT env-preserving (8 секретов), `prune:false, pullImage:true`, mem_limit 512m.
6. Live smoke (crawl menu-страниц + viewModel, не только `/`).
7. Rollback = образ-тег (текущий v2-тег).
### Breaking changes v3 (минимизированы back-compat шимом)
- `s3ForcePathStyle``forcePathStyle` — рантайм **НЕ breaking** (back-compat шим в storage.js v3 читает оба ключа). Config-правка recommended (forward-clean), не обязательна.
- `sslEnabled` (config) + `S3_SSL_ENABLED` (env) — удалены (unused), игнорируются если остались.
- `aws-sdk` / `s3fs` удалены из snolla deps (s3fs был unused). Consumer-код, импортивший их из snolla-deps напрямую (неофициальная поверхность) — сломается; по коду 6 сайтов такого нет.
- `populate-theme-store.mjs` мигрирован v2→v3 (script, не рантайм) — admin-side, рантайм не трогает.
--- ---
## S3-клиент совместимость (audit — сделано) ## S3-клиент совместимость (audit — сделано)
@@ -51,6 +115,7 @@
> Все шаги — на books-vds (`root@89.253.255.133`, ключ `~/.ssh/id_ed25519_books_ops`). > Все шаги — на books-vds (`root@89.253.255.133`, ключ `~/.ssh/id_ed25519_books_ops`).
> Transparent: НЕ меняем hostname/creds/имя-контейнера для apps. Только swap бэкенда под тем же именем. > Transparent: НЕ меняем hostname/creds/имя-контейнера для apps. Только swap бэкенда под тем же именем.
> Креды для `mc alias` — из `pass show minio-vds/full-env` (`MINIO_ROOT_USER`/`MINIO_ROOT_PASSWORD`).
## A1. Shared `minio` 2020→2025 ## A1. Shared `minio` 2020→2025
@@ -59,20 +124,23 @@
**Бакеты, что остаются на shared minio (slovo):** `books` (37442 obj, 1.2 GiB), `ozon` (0B), `manuals` (0B), `test`/`upload`/`imgproxytest`. + почистить bookva-дубли (см. A3). **Бакеты, что остаются на shared minio (slovo):** `books` (37442 obj, 1.2 GiB), `ozon` (0B), `manuals` (0B), `test`/`upload`/`imgproxytest`. + почистить bookva-дубли (см. A3).
```bash ```bash
# Креды из pass (НЕ хардкодить, НЕ коммитить):
source <(pass show minio-vds/full-env | grep -E 'MINIO_ROOT_(USER|PASSWORD)')
# 0. Стоп-условие: books apps живы на старом minio (baseline). Снимок логов. # 0. Стоп-условие: books apps живы на старом minio (baseline). Снимок логов.
ssh root@89.253.255.133 'docker logs --tail 50 books-api; docker exec minio sh -c "echo ok"' ssh root@89.253.255.133 'docker logs --tail 50 books-api; docker exec minio sh -c "echo ok"'
# 1. Новый 2025 контейнер, новый data-dir, тот же network=proxy, креды из env # 1. Новый 2025 контейнер, новый data-dir, тот же network=proxy, креды из env
ssh root@89.253.255.133 'mkdir -p /usr/docker/minio-new/data' ssh root@89.253.255.133 'mkdir -p /usr/docker/minio-new/data'
# compose: image minio/minio:RELEASE.2025-09-07..., command server /data --console-address :9001, # compose: image minio/minio:RELEASE.2025-09-07..., command server /data --console-address :9001,
# env MINIO_ROOT_USER/PASSWORD (== AKIAJ2.../7o0Q...), volume /usr/docker/minio-new/data:/data, # env MINIO_ROOT_USER/PASSWORD (== $MINIO_ROOT_USER/$MINIO_ROOT_PASSWORD), volume /usr/docker/minio-new/data:/data,
# network proxy, traefik labels minio-console.kzntsv.site→:9001 (новая консоль) — написать compose-файл # network proxy, traefik labels minio-console.kzntsv.site→:9001 (новая консоль) — написать compose-файл
# (template ниже; НЕ поднимать до готовности миррора) # (template ниже; НЕ поднимать до готовности миррора)
# 2. mc mirror slovo-бакетов old(2020) → new(2025) # 2. mc mirror slovo-бакетов old(2020) → new(2025)
docker run --rm --network host --entrypoint sh minio/mc:latest -c ' docker run --rm --network host --entrypoint sh minio/mc:latest -c '
mc alias set old http://127.0.0.1:9000 AKIAJ2YJP72W6ZHCRE6Q "7o0Q4NjE5GLkdC48r0oZFEnqddjPNLqtCk+ZEh+S" >/dev/null mc alias set old http://127.0.0.1:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null
mc alias set new http://127.0.0.1:900X AKIAJ2YJP72W6ZHCRE6Q "7o0Q4NjE5GLkdC48r0oZFEnqddjPNLqtCk+ZEh+S" >/dev/null mc alias set new http://127.0.0.1:900X "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null
for b in books ozon manuals test upload imgproxytest; do mc mb --ignore-existing new/$b; mc mirror --overwrite old/$b new/$b; done for b in books ozon manuals test upload imgproxytest; do mc mb --ignore-existing new/$b; mc mirror --overwrite old/$b new/$b; done
' '
# 3. Verify per-bucket object count old==new # 3. Verify per-bucket object count old==new
@@ -91,11 +159,12 @@ docker run --rm --network host --entrypoint sh minio/mc:latest -c '
Контейнер `bookva-minio`, volume `bookva-minio-data` (37074 obj в бакете `books`). НЕ пуст (мигрирован ~2026-05). Console наружу НЕ выставляем. Контейнер `bookva-minio`, volume `bookva-minio-data` (37074 obj в бакете `books`). НЕ пуст (мигрирован ~2026-05). Console наружу НЕ выставляем.
```bash ```bash
source <(pass show minio-vds/full-env | grep -E 'MINIO_ROOT_(USER|PASSWORD)')
# 1. Новый 2025 контейнер bookva-minio-new (новый volume bookva-minio-data-new), тот же creds # 1. Новый 2025 контейнер bookva-minio-new (новый volume bookva-minio-data-new), тот же creds
# 2. mc mirror bookva-minio(2020):9001 → bookva-minio-new(2025):900X, бакет books (37074 obj) # 2. mc mirror bookva-minio(2020):9001 → bookva-minio-new(2025):900X, бакет books (37074 obj)
docker run --rm --network host --entrypoint sh minio/mc:latest -c ' docker run --rm --network host --entrypoint sh minio/mc:latest -c '
mc alias set bvold http://127.0.0.1:9001 AKIAJ2YJP72W6ZHCRE6Q "7o0Q4NjE5GLkdC48r0oZFEnqddjPNLqtCk+ZEh+S" >/dev/null mc alias set bvold http://127.0.0.1:9001 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null
mc alias set bvnew http://127.0.0.1:900X AKIAJ2YJP72W6ZHCRE6Q "7o0Q4NjE5GLkdC48r0oZFEnqddjPNLqtCk+ZEh+S" >/dev/null mc alias set bvnew http://127.0.0.1:900X "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null
mc mb --ignore-existing bvnew/books; mc mirror --overwrite bvold/books bvnew/books mc mb --ignore-existing bvnew/books; mc mirror --overwrite bvold/books bvnew/books
' '
# 3. Verify count: mc ls --recursive bvold/books | wc -l == mc ls --recursive bvnew/books | wc -l (37074) # 3. Verify count: mc ls --recursive bvold/books | wc -l == mc ls --recursive bvnew/books | wc -l (37074)
@@ -107,7 +176,7 @@ docker run --rm --network host --entrypoint sh minio/mc:latest -c '
## A3. Почистить bookva-дубли из shared `books` (после A1, перед mirror-verify) ## A3. Почистить bookva-дубли из shared `books` (после A1, перед mirror-verify)
В shared `books` остались 95+4 bookva-файлов от до-миграции (дубли того, что уже на bookva-minio). Bookva-unique ключи вычислить из bookva-db и удалить из shared `books`. В shared `books` остались 95+4 bookva-файла от до-миграции (дубли того, что уже на bookva-minio). Bookva-unique ключи вычислить из bookva-db и удалить из shared `books`.
```bash ```bash
# Выгрузить bookva-unique s3-пути (на books-vds): # Выгрузить bookva-unique s3-пути (на books-vds):
@@ -138,10 +207,11 @@ docker exec -i bookva-db mariadb -ubooks -pFNud4Um47y books -N -e \
vds minio уже 2025-09-07. Stale-копия от 2026-05 — перезаписать свежим миррором. vds minio уже 2025-09-07. Stale-копия от 2026-05 — перезаписать свежим миррором.
```bash ```bash
source <(pass show minio-vds/full-env | grep -E 'MINIO_ROOT_(USER|PASSWORD)')
# На books-vds (источник) → vds minio (назначение), через mc. Creds одинаковые. # На books-vds (источник) → vds minio (назначение), через mc. Creds одинаковые.
docker run --rm --network host --entrypoint sh minio/mc:latest -c ' docker run --rm --network host --entrypoint sh minio/mc:latest -c '
mc alias set src http://127.0.0.1:9000 AKIAJ2YJP72W6ZHCRE6Q "7o0Q4NjE5GLkdC48r0oZFEnqddjPNLqtCk+ZEh+S" >/dev/null mc alias set src http://127.0.0.1:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null
mc alias set dst https://minio.vds.kzntsv.site AKIAJ2YJP72W6ZHCRE6Q "7o0Q4NjE5GLkdC48r0oZFEnqddjPNLqtCk+ZEh+S" --insecure >/dev/null mc alias set dst https://minio.vds.kzntsv.site "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" --insecure >/dev/null
for b in galleries artmone themes assets pilorama98 maxmind obsidian strapi; do for b in galleries artmone themes assets pilorama98 maxmind obsidian strapi; do
mc mb --ignore-existing dst/$b mc mb --ignore-existing dst/$b
mc mirror --overwrite --preserve src/$b dst/$b --insecure mc mirror --overwrite --preserve src/$b dst/$b --insecure
@@ -172,7 +242,7 @@ docker build -f deploy/Dockerfile --build-arg VERDACCIO_TOKEN=<from pass vds-kzn
-t registry.kzntsv.site/<site>-web:<sha> . -t registry.kzntsv.site/<site>-web:<sha> .
docker push registry.kzntsv.site/<site>-web:<sha> docker push registry.kzntsv.site/<site>-web:<sha>
``` ```
Затем parity-gate (throwaway staging `:50XX`) + Portainer PUT env-preserving (по `snolla-live-prod-inplace-image-bump`). Smoke каждого сайта (crawl menu pages + viewModel, не только /). Затем parity-gate (throwaway staging `:50XX`) + Portainer PUT env-preserving (по [[snolla-live-prod-inplace-image-bump]]). Smoke каждого сайта (crawl menu pages + viewModel, не только /).
## B4. .NET catch-all админ (воркстейшн) — s3 endpoint ## B4. .NET catch-all админ (воркстейшн) — s3 endpoint

View File

@@ -67,6 +67,11 @@ Culture `en`. Спека: [[snolla-local-admin-and-on-snolla-migration-design]]
9. **Live-smoke С VDS + external** — `https://on.snolla.com/{robots.txt,/,/sitemap.xml,/yandex_…}` = 200, 9. **Live-smoke С VDS + external** — `https://on.snolla.com/{robots.txt,/,/sitemap.xml,/yandex_…}` = 200,
`/c` = 404 parity. TLS verify `ssl_verify_result=0` (trusted LE chain). Homepage **byte-identical** prod-HTML. `/c` = 404 parity. TLS verify `ssl_verify_result=0` (trusted LE chain). Homepage **byte-identical** prod-HTML.
## In-place bumps (после cutover)
- **07db7e3 — MinIO split config-endpoint (v2, 2026-07-30).** In-place bump стека 22 `473923e494db→07db7e3` без правки `package.json`: только `config/production.json` `s3.endpoint` `minio.kzntsv.site→minio.vds.kzntsv.site`. snolla остался 0.42.1 (aws-sdk v2). Пилот S3-direct-path — theme asset 200 97324 B == live, v2 vs vds MinIO 2025 работает без @smithy pin. Rollback-тег `473923e494db`. См. [[minio-split-cutover-runbook]] §B3 (Track B).
- **eb8c143 — v3 bump (aws-sdk v2→v3, 2026-07-30T11:28Z).** End-goal (user). `@snollajs/snolla 0.42.1→0.43.2` в `apps/web/package.json` + `resolutions` (@aws-sdk/client-s3 3.1005.0 exact + @smithy chain 5.3.11) в root `package.json` (optional determinism, single-instance — live verify доказал что 5.6.12 тоже работает, pin для version-stability). Commit `eb8c143` pushed. Build на VDS (archive → `~/build/on-snolla` → `docker build -f deploy/Dockerfile --build-arg VERDACCIO_TOKEN`) → `registry.kzntsv.site/on-snolla:eb8c143` (+`:latest`). Throwaway staging :5078 из env live-контейнера (8 секретов) → parity-gate GREEN (theme asset 200 97324 B byte-identical, sitemapindex+3 sub-sitemaps byte-identical, `/c` 404 parity). Portainer PUT stack 22 env-preserving (8/8, node in-memory `put-stack` — НЕ PS Invoke-RestMethod), `prune:false, pullImage:true`, `mem_limit 512m` preserved. Live smoke GREEN: `/` 200, robots/sitemap/sub-sitemaps 200, `/yandex` 200, theme asset 200 97324 B (v3 aws-sdk v3 S3-direct read из vds MinIO 2025). TLS не тронут (LE до Oct 18). Back-compat шим `s3ForcePathStyle`→`forcePathStyle` (v2-key ещё читается) — config-правки не требовались. **Rollback = `07db7e3`** (v2, жив в registry). См. [[minio-split-cutover-runbook]] §B3-v3 + [[snolla-live-prod-inplace-image-bump]].
## Гочи (специфичные) ## Гочи (специфичные)
- **snolla `robotsTxt` middleware падает на undefined `app.locals.domain`** — on.snolla.com НЕ имеет row в - **snolla `robotsTxt` middleware падает на undefined `app.locals.domain`** — on.snolla.com НЕ имеет row в
MoreThenCms `Domains` (served by primaryDomain без per-domain row). `robotsTxt.js` читает MoreThenCms `Domains` (served by primaryDomain без per-domain row). `robotsTxt.js` читает

View File

@@ -39,6 +39,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
- [labtools.pro-vds-deploy-runbook](concepts/labtools.pro-vds-deploy-runbook.md) — labtools.pro snolla-каталог на VDS (стек 19): сборка/env/cutover 07-02 + **0.42.1 in-place bump 07-05** (образ `labtools-pro:0610432`, order-парити 3 секции) - [labtools.pro-vds-deploy-runbook](concepts/labtools.pro-vds-deploy-runbook.md) — labtools.pro snolla-каталог на VDS (стек 19): сборка/env/cutover 07-02 + **0.42.1 in-place bump 07-05** (образ `labtools-pro:0610432`, order-парити 3 секции)
- [tandemmebel-vds-deploy-runbook](concepts/tandemmebel-vds-deploy-runbook.md) — tandemmebel.ru snolla-блог-портфолио на VDS (стек 20): cutover 07-12 (DNS reg.ru, LE) + **0.42.1 in-place bump 07-12** (образ `tandemmebel:0cd9351`, 184/184 parity, /articles 404 benign) - [tandemmebel-vds-deploy-runbook](concepts/tandemmebel-vds-deploy-runbook.md) — tandemmebel.ru snolla-блог-портфолио на VDS (стек 20): cutover 07-12 (DNS reg.ru, LE) + **0.42.1 in-place bump 07-12** (образ `tandemmebel:0cd9351`, 184/184 parity, /articles 404 benign)
- [minio-imgproxy-on-vds](concepts/minio-imgproxy-on-vds.md) — MinIO+imgproxy stack на VDS, миграция с upgrade 2020→2025 + DNS swap pending - [minio-imgproxy-on-vds](concepts/minio-imgproxy-on-vds.md) — MinIO+imgproxy stack на VDS, миграция с upgrade 2020→2025 + DNS swap pending
- [minio-split-cutover-runbook](concepts/minio-split-cutover-runbook.md) — разнос MinIO-контента: Track A books-vds 2020→2025 (shared+bookva) + Track B CMS-медиа → vds 2025. Progress: B1 миррор✅ B2 DNS-flip✅ B3 on-snolla v2-пилот✅ LIVE, B3v3 (snolla 0.43.2 опубликована, live verify ЗЕЛЁНЫЙ, resolutions optional) ⚡READY, B4/B5/Track A TODO. v3 — конечная цель.
- [morethencms-null-settingsdata-https-502](concepts/morethencms-null-settingsdata-https-502.md) — MoreThenCms тенант с `Sites.SettingsData=NULL` → 502 только на HTTPS (нет `httpSecure` → KeyNotFound); fix = UPDATE + recycle. maljarka 2026-06-08 - [morethencms-null-settingsdata-https-502](concepts/morethencms-null-settingsdata-https-502.md) — MoreThenCms тенант с `Sites.SettingsData=NULL` → 502 только на HTTPS (нет `httpSecure` → KeyNotFound); fix = UPDATE + recycle. maljarka 2026-06-08
- [snolla-admin-appdata-acl-500-after-scp-migration](concepts/snolla-admin-appdata-acl-500-after-scp-migration.md) — админский delete/upload ассета → 500: app pool имел на `App_Data` только RX после scp-миграции → `File.Delete` UnauthorizedAccessException. Fix = icacls Modify. + split-brain: админка пишет Local, боевой app читает MinIO - [snolla-admin-appdata-acl-500-after-scp-migration](concepts/snolla-admin-appdata-acl-500-after-scp-migration.md) — админский delete/upload ассета → 500: app pool имел на `App_Data` только RX после scp-миграции → `File.Delete` UnauthorizedAccessException. Fix = icacls Modify. + split-brain: админка пишет Local, боевой app читает MinIO
- [snolla-local-admin-and-on-snolla-migration-design](concepts/snolla-local-admin-and-on-snolla-migration-design.md) — design: Task A восстановить локальный .NET-админ (catch-all IIS `snolla`, hosts-override, MinIO drop-in) + Task B on.snolla.com → VDS как Node snolla-app - [snolla-local-admin-and-on-snolla-migration-design](concepts/snolla-local-admin-and-on-snolla-migration-design.md) — design: Task A восстановить локальный .NET-админ (catch-all IIS `snolla`, hosts-override, MinIO drop-in) + Task B on.snolla.com → VDS как Node snolla-app

View File

@@ -2,6 +2,8 @@
Append-only log of wiki operations (ingests, promotions, lints, migrations). Append-only log of wiki operations (ingests, promotions, lints, migrations).
## [2026-07-30] migrate | RELOCATE runbook `scripts/minio-split-cutover/runbook.md` → `concepts/minio-split-cutover-runbook.md` (дисциплина: runbook'и → `.wiki/concepts/`, не `scripts/`; `scripts/` для executable). +UPDATE content: v3-секция (snolla 0.43.2 опубликована, live MinIO verify ЗЕЛЁНЫЙ оба конфига, resolutions=optional determinism НЕ mandatory — regression-гипотеза v3 SigV4 vs MinIO НЕ воспроизвелась end-to-end, «CONFIRMED» framing откатан), креды нормализованы → `pass show minio-vds/full-env` (были plaintext в bash-примерах — wiki-конвенция «креды в pass, не в git»). +index.md строка. Старый `scripts/minio-split-cutover/` удалён (в нём кроме runbook'а ничего не было). Cross-ref [[on-snolla-vds-deploy-runbook]], [[minio-imgproxy-on-vds]], [[snolla-live-prod-inplace-image-bump]], [[../entities/vds-kzntsv]], [[../entities/books-vds]]. Related memory: admin `aws-sdk-v3-smithy-sigv4-minio-regression`, `aws-sdk-v2-minio-2025-works-no-smithy-pin`.
## [2026-07-29] implement | NEW concepts/snolla-local-admin-https-binding.md + UPDATE index.md (concepts +2 строки) — локальный .NET-админ snolla (catch-all IIS `snolla`) переведён на HTTPS. Повод: `https://pilorama98.snolla.com/admin` → 404 → ERR_CONNECTION_CLOSED. Корень 404: `pilorama98.snolla.com` не был в hosts-override → реальный DNS → VDS `89.253.255.94` → traefik без роута (системный прокси `127.0.0.1:10808` маскировал «server 127.0.0.1» в curl). pilorama98 — реальный сайт в `dbo.Sites` (Alias=pilorama98, PrimaryDomain=pilorama98.ru, Live), вне тиража-5 из design-дока. Корень ERR_CONNECTION_CLOSED: браузер HSTS-апгрейдил http→https, а локальный IIS без 443. Решение: **IIS-native self-signed wildcard `*.snolla.com` на :443 + Trusted Root**, НЕ traefik (локальный acme.json пуст → LE на snolla.com нет; traefik-as-TLS-terminator = NAT-loopback/docker.sock/URL-Rewrite/SERVER_PORT-leak готчи без выгоды). Скрипт elevated (UAC): `New-SelfSignedCertificate -Subject '*.snolla.com' -DnsName '*.snolla.com','snolla.com' -TextExtension EKU serverAuth` (гоча: `-DnsName` конфликтует с ручным SAN `2.5.29.17` → SAN через `-DnsName`) → копия в `Cert:\LocalMachine\Root` → `New-WebBinding snolla https 443 *` + `AddSslCertificate` + restart. Cert thumb `6E2212B4C13BD28E2FF680322F11741193E8C619`, SAN `*.snolla.com,snolla.com`, 10 лет — покрывает все alias'ы. hosts: добавлен `pilorama98.snolla.com` (elevated, построчно — `Get-Content -Raw` мог опустошить файл). Результат: `https://<alias>.snolla.com/admin/account/login` → 200 форма SNOLLA (pilorama98/kupimknigi/internal/tandemmebel верифицированы). **Голый `/admin` → 302 `/login` → 301 `https://www.<PrimaryDomain>/`** — предсуществующее поведение CMS (оператор подтвердил: «так и было» на RUVDS), не поломка миграции; рабочий entry-point `/admin/account/login`. `on.snolla.com` → 404: hosts стоит `internal.snolla.com` (реальный alias сайта `on` = `internal`), не `on` (design-док писал `on`). Trade-off: self-signed не LE — допустимо (админка локальная, FW закрыт). +index.md (2 строки: design-док ранее не был индексирован + новый page). Cross-ref [[snolla-local-admin-and-on-snolla-migration-design]], [[traefik-on-windows-docker-desktop]], [[stostayer-admin-minio-config]]. ## [2026-07-29] implement | NEW concepts/snolla-local-admin-https-binding.md + UPDATE index.md (concepts +2 строки) — локальный .NET-админ snolla (catch-all IIS `snolla`) переведён на HTTPS. Повод: `https://pilorama98.snolla.com/admin` → 404 → ERR_CONNECTION_CLOSED. Корень 404: `pilorama98.snolla.com` не был в hosts-override → реальный DNS → VDS `89.253.255.94` → traefik без роута (системный прокси `127.0.0.1:10808` маскировал «server 127.0.0.1» в curl). pilorama98 — реальный сайт в `dbo.Sites` (Alias=pilorama98, PrimaryDomain=pilorama98.ru, Live), вне тиража-5 из design-дока. Корень ERR_CONNECTION_CLOSED: браузер HSTS-апгрейдил http→https, а локальный IIS без 443. Решение: **IIS-native self-signed wildcard `*.snolla.com` на :443 + Trusted Root**, НЕ traefik (локальный acme.json пуст → LE на snolla.com нет; traefik-as-TLS-terminator = NAT-loopback/docker.sock/URL-Rewrite/SERVER_PORT-leak готчи без выгоды). Скрипт elevated (UAC): `New-SelfSignedCertificate -Subject '*.snolla.com' -DnsName '*.snolla.com','snolla.com' -TextExtension EKU serverAuth` (гоча: `-DnsName` конфликтует с ручным SAN `2.5.29.17` → SAN через `-DnsName`) → копия в `Cert:\LocalMachine\Root` → `New-WebBinding snolla https 443 *` + `AddSslCertificate` + restart. Cert thumb `6E2212B4C13BD28E2FF680322F11741193E8C619`, SAN `*.snolla.com,snolla.com`, 10 лет — покрывает все alias'ы. hosts: добавлен `pilorama98.snolla.com` (elevated, построчно — `Get-Content -Raw` мог опустошить файл). Результат: `https://<alias>.snolla.com/admin/account/login` → 200 форма SNOLLA (pilorama98/kupimknigi/internal/tandemmebel верифицированы). **Голый `/admin` → 302 `/login` → 301 `https://www.<PrimaryDomain>/`** — предсуществующее поведение CMS (оператор подтвердил: «так и было» на RUVDS), не поломка миграции; рабочий entry-point `/admin/account/login`. `on.snolla.com` → 404: hosts стоит `internal.snolla.com` (реальный alias сайта `on` = `internal`), не `on` (design-док писал `on`). Trade-off: self-signed не LE — допустимо (админка локальная, FW закрыт). +index.md (2 строки: design-док ранее не был индексирован + новый page). Cross-ref [[snolla-local-admin-and-on-snolla-migration-design]], [[traefik-on-windows-docker-desktop]], [[stostayer-admin-minio-config]].
## [2026-07-22] fix | NEW concepts/stostayer-admin-minio-config.md — локальная .NET-админка stostayer (`C:\sites\stostayer\Web.config`, IIS :8090) переведена на рабочий stostayer MinIO. Исходно S3-провайдеры (`MoreThenCms.FileStorage.S3` в `bin/`) уже стояли, но с 3 багами: (1) чужие креды `AKIAJ2YJP72W6ZHCRE6Q` = books-vds/snolla root-ключ (копипаст из snolla catch-all admin, не заменён на stostayer-свои → "Access Key Id does not exist"); (2) `serviceURL=https://minio.stostayer.ru` — НЕ S3 API-порт ("S3 API Requests must be made to API port"), прод юзает `minio-api.stostayer.ru`; (3) `authenticationRegion="local"` → SigV4 регион-мismatch → `AmazonS3Exception: the region is wrong; expecting 'us-west-1'` (400) на `GalleriesStorage.EnsureKeyPrefixExists` (`ToolsController.ImagePreview` → `CreatePreview`). Креды stostayer MinIO **не в pass** — лежат в `~/projects/stostayer.new/packages/web/config/default.json` → `s3`: accessKey `stayer_minio`, endpoint `https://minio-api.stostayer.ru`, region `us-west-1`. Fix: 3 глобальные замены × 9 S3-блоков в Web.config (accessKey/secretKey[XML-escaped `>`/`&`]/serviceURL) + region `local`→`us-west-1`; бэкап `Web.config.bak-2026-07-22`; IIS recycle, лог чист. mc `alias set` + ListBuckets OK (10 бакетов: assets/galleries/themes/…); `assets/9cf0a8e52cf144619fd290606a146d35/` несёт реальные файлы. Acceptance оператором: картинки грузятся. Админка=прод единое хранилище, ручное зеркалирование в `App_Data` упразднено. +index.md concepts-строка. Cross-ref [[galleries-storage-class-local-not-s3]], [[snolla-admin-appdata-acl-500-after-scp-migration]], [[minio-imgproxy-on-vds]]. ## [2026-07-22] fix | NEW concepts/stostayer-admin-minio-config.md — локальная .NET-админка stostayer (`C:\sites\stostayer\Web.config`, IIS :8090) переведена на рабочий stostayer MinIO. Исходно S3-провайдеры (`MoreThenCms.FileStorage.S3` в `bin/`) уже стояли, но с 3 багами: (1) чужие креды `AKIAJ2YJP72W6ZHCRE6Q` = books-vds/snolla root-ключ (копипаст из snolla catch-all admin, не заменён на stostayer-свои → "Access Key Id does not exist"); (2) `serviceURL=https://minio.stostayer.ru` — НЕ S3 API-порт ("S3 API Requests must be made to API port"), прод юзает `minio-api.stostayer.ru`; (3) `authenticationRegion="local"` → SigV4 регион-мismatch → `AmazonS3Exception: the region is wrong; expecting 'us-west-1'` (400) на `GalleriesStorage.EnsureKeyPrefixExists` (`ToolsController.ImagePreview` → `CreatePreview`). Креды stostayer MinIO **не в pass** — лежат в `~/projects/stostayer.new/packages/web/config/default.json` → `s3`: accessKey `stayer_minio`, endpoint `https://minio-api.stostayer.ru`, region `us-west-1`. Fix: 3 глобальные замены × 9 S3-блоков в Web.config (accessKey/secretKey[XML-escaped `>`/`&`]/serviceURL) + region `local`→`us-west-1`; бэкап `Web.config.bak-2026-07-22`; IIS recycle, лог чист. mc `alias set` + ListBuckets OK (10 бакетов: assets/galleries/themes/…); `assets/9cf0a8e52cf144619fd290606a146d35/` несёт реальные файлы. Acceptance оператором: картинки грузятся. Админка=прод единое хранилище, ручное зеркалирование в `App_Data` упразднено. +index.md concepts-строка. Cross-ref [[galleries-storage-class-local-not-s3]], [[snolla-admin-appdata-acl-500-after-scp-migration]], [[minio-imgproxy-on-vds]].

View File

@@ -34,7 +34,7 @@
services: services:
on-snolla: on-snolla:
container_name: on-snolla container_name: on-snolla
image: registry.kzntsv.site/on-snolla:07db7e3 # git-sha on.snolla.com master 07db7e3 (snolla 0.42.1, s3.endpoint -> minio.vds.kzntsv.site). rollback-тег в registry: 473923e494db (pred. endpoint minio.kzntsv.site/books-vds, жив). image: registry.kzntsv.site/on-snolla:eb8c143 # git-sha on.snolla.com master eb8c143 (snolla 0.43.2 aws-sdk v3 + @smithy resolutions 5.3.11, s3.endpoint -> minio.vds.kzntsv.site). v3 cutover 2026-07-30 (cм. .wiki/concepts/minio-split-cutover-runbook §B3-v3). rollback-тег в registry: 07db7e3 (pred. snolla 0.42.1 v2, жив — был live 2026-07-30 до v3). pred-rollback: 473923e494db (endpoint minio.kzntsv.site/books-vds).
restart: unless-stopped restart: unless-stopped
mem_limit: 512m # guardrail: snolla baseline ~100-200M; OOM -> restart. standalone-compose -> mem_limit (НЕ deploy.resources, swarm-only). mem_limit: 512m # guardrail: snolla baseline ~100-200M; OOM -> restart. standalone-compose -> mem_limit (НЕ deploy.resources, swarm-only).
environment: environment: