From e001b8e331e75c50be40acc6636c2cd9b2ad0a1a Mon Sep 17 00:00:00 2001 From: vitya Date: Fri, 12 Jun 2026 11:56:19 +0300 Subject: [PATCH] feat(books-backup): bookva-es snapshot via Portainer path.repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bookva-es (отдельный ES 7.10, Portainer stack 37) не снапшотился — path.repo не сконфигурирован. Пересоздан через Portainer API (PUT /api/stacks/37) с path.repo=/snapshots + bind /usr/docker/bookva-es/snapshots (uid 1000:0); внешний том bookva-es-data сохранён (epz/products целы). Repo kreknin зарегистрирован. Добавлен Step 2b (bookva-es snapshot + prune) в run.sh. Gotcha пойман на проверке приёмника ДО коммита: оба ES-каталога называются `snapshots` → как отдельные rsync-источники сливаются в один dest/snapshots/ и портят оба репо (видно по двойному index-N). Fix: источник bookva-es = родительский /usr/docker/bookva-es (basename bookva-es → dest/bookva-es/snapshots/). Verified green: BOOKS-VDS backup OK 10m28s, на kreknin раздельно snapshots/ (slovo, index-41, 795M) + bookva-es/snapshots/ (index-4, 801M), по одному index-N в каждом → оба независимо рестораблельны. Закрывает .tasks/bookva-es-snapshot-repo.md (🟢). bookva tenant полностью покрыт (db/mongo/minio/es). Co-Authored-By: Claude Opus 4.8 (1M context) --- .tasks/STATUS.md | 1 + .tasks/bookva-es-snapshot-repo.md | 4 +-- .wiki/concepts/backup-inventory-2026-06.md | 2 +- .wiki/entities/books-vds.md | 8 ++--- scripts/books-vds-backup-daily-kreknin/run.sh | 31 ++++++++++++++++++- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index b70b5bc..faa3d6f 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -1,4 +1,5 @@ # Admin Task Board +_Updated: 2026-06-12 (3) — 🟢 **bookva-es snapshot done** (не отложен). Portainer stack 37 пересоздан с `path.repo=/snapshots`+bind (PUT API, том цел, epz/products уцелели), repo `kreknin` зарегистрирован, snapshot-блок в `run.sh`. Поймана коллизия basename `snapshots` (оба ES-каталога одноимённы → сливались в один dest-репо, порча обоих) → источник bookva-es = родительский `/usr/docker/bookva-es`. Verified: `BOOKS-VDS backup OK 10m28s`, на kreknin раздельно `snapshots/`(slovo index-41) + `bookva-es/snapshots/`(index-4). Таска `bookva-es-snapshot-repo` 🟢 closed._ _Updated: 2026-06-12 (2) — 🟢 **bookva-* backup gap закрыт.** bookva tenant (db/mongo/es/minio, поднят 26.05) не бэкапился — books-скрипт написан 25.05 до bookva, покрытие не расширили (висело wiki-follow-up #2). Добавлены bookva-db (тот же root pw), bookva-mongo (no-auth), bookva-minio (raw volume) в `books-vds-backup-daily-kreknin/run.sh`; деплой == репо (`.bak-pre-bookva`). Verified green: `BOOKS-VDS backup OK 10m42s`, артефакты на kreknin (bookva-mariadb 257M, bookva-mongo 3.2M, bookva-minio 1.4G). bookva-es отложен → `bookva-es-snapshot-repo` (покрыт slovo-снапшотом, индексы идентичны). Правило в память: новый stateful → бэкап в том же коммите._ _Updated: 2026-06-12 — 🔴→🟢 **MSSQL backup incident + estate backup audit.** VDS daily backup падал с 12.06 (line 108, exit 1): mssql-блок (added 11.06) использовал `WITH ... INIT` → упирался в компрессованный media-header майских `.bak` (Express не пишет COMPRESSION) → молча падал первым cron-запуском. **5 боевых CMS-баз 3 недели без offsite-копии.** Fix: `INIT`→`FORMAT`, прогон verified (MoreThenCms 910M/StayerCalculator 528M/StayerPrice 39M/TireService 4.5M/stostayer 990M на kreknin). Репо-копия `run.sh` синхронизирована (mssql-блока не было). Concept: `.wiki/concepts/mssql-on-vds.md` gotcha#2. **Estate backup-аудит** → `.wiki/concepts/backup-inventory-2026-06.md`: ✅ openwrt UCI backup настроен (cron 03:30 → kreknin, restricted forced-command key); ⚪ заведена `kreknin-self-backup` (#1 SPOF, на потом); nl-vds x-ui.db — user: не нужен; windows-host stale script — user: забыть._ _Updated: 2026-06-08 — 🟢 ad-hoc fix `maljarka.tandemmebel.ru` (iis-migration follow-up): домен переехал на RUVDS корректно (DNS/TLS/IIS ок), но отдавал 502 **только на HTTPS**. Root cause не в миграции: у тенанта maljarka `dbo.Sites.SettingsData=NULL` (нет блока `httpSecure`) → MoreThenCms `SnollaMiddleware` бросает KeyNotFound на HTTPS-ветке → 502; по HTTP 200. Fix: `UPDATE dbo.Sites SET SettingsData='{httpSecure:enableHttps=true,…}' WHERE SiteId=a2476738… AND SettingsData IS NULL` + `Restart-WebAppPool snolla`. Verified maljarka:443→200 (server-local + external по 80.64.31.36), kupimknigi не задет. Audit: maljarka — единственный NULL-сайт с :443-биндингом из 25. rimiz degraded по др. причине. Concept: `.wiki/concepts/morethencms-null-settingsdata-https-502.md`._ diff --git a/.tasks/bookva-es-snapshot-repo.md b/.tasks/bookva-es-snapshot-repo.md index 87323a3..6c3b729 100644 --- a/.tasks/bookva-es-snapshot-repo.md +++ b/.tasks/bookva-es-snapshot-repo.md @@ -1,7 +1,7 @@ # bookva-es-snapshot-repo — отдельный ES-снапшот для bookva tenant -**Status:** ⚪ backlog — заведена 2026-06-12 при добавлении bookva в backup. -**Priority:** низкий (данные покрыты по факту — см. ниже). +**Status:** 🟢 closed 2026-06-12 (в ту же сессию). Сделано полностью — не отложено. +**Close note:** Portainer stack 37 пересоздан (PUT API) с `path.repo=/snapshots` + bind `/usr/docker/bookva-es/snapshots` (1000:0), том bookva-es-data сохранён (epz/products целы). Repo `kreknin` зарегистрирован, snapshot-блок добавлен в `run.sh`. Поймана и устранена коллизия basename `snapshots` (rsync источник bookva-es = родительский `/usr/docker/bookva-es`). Verified green: `BOOKS-VDS backup OK 10m28s`, на kreknin раздельно `snapshots/`(slovo, index-41) и `bookva-es/snapshots/`(index-4). ## Контекст diff --git a/.wiki/concepts/backup-inventory-2026-06.md b/.wiki/concepts/backup-inventory-2026-06.md index 49179ca..2588d7e 100644 --- a/.wiki/concepts/backup-inventory-2026-06.md +++ b/.wiki/concepts/backup-inventory-2026-06.md @@ -34,7 +34,7 @@ CMS-баз на [[../entities/vds-kzntsv]] **3 недели не имели offs |---|---|---|---| | 1 | **kreknin сам не бэкапится** — SPOF всей estate (1 том 7 ТБ, RAID не подтверждён; смерть `/volume1` = одновременная потеря offsite-копий ВСЕХ машин) | «задача, но на потом» | ⚪ заведена `[[../../.tasks/kreknin-self-backup]]` (#1 по риску) | | 2 | **openwrt UCI** — единственный публичный ingress всех CMS, без копии | «можешь сделать» | ✅ **СДЕЛАНО** — см. ниже | -| 3 | **bookva-* на books-vds** (`bookva-db/mongo/es/minio` tenant-данные) не дампятся/не rsync'ятся | «немедленно делать» | ✅ **СДЕЛАНО 2026-06-12** — db/mongo/minio в daily-backup (verified); bookva-es отложен (`[[../../.tasks/bookva-es-snapshot-repo]]`, покрыт slovo-снапшотом) | +| 3 | **bookva-* на books-vds** (`bookva-db/mongo/es/minio` tenant-данные) не дампятся/не rsync'ятся | «немедленно делать» | ✅ **СДЕЛАНО 2026-06-12** — db/mongo/minio/es в daily-backup, все verified на kreknin (включая bookva-es snapshot через Portainer path.repo) | | 4 | **nl-vds-3xui `x-ui.db`** — профили + Reality-ключи только на хосте | «не нужен» | ⏸ accepted (won't-do) | | 5 | **windows-host stale script** — таргетит удалённые 08.06 ресурсы | «забыть, не актуально» | ⏸ accepted (ignore) | diff --git a/.wiki/entities/books-vds.md b/.wiki/entities/books-vds.md index 38b6e7e..b02c501 100644 --- a/.wiki/entities/books-vds.md +++ b/.wiki/entities/books-vds.md @@ -108,14 +108,14 @@ Recreate ломает access всему остальному (traefik) или с Daily 06:00 MSK → kreknin. См. [[../sources/books-vds-backup-daily-kreknin-2026-05-25]]. Pipeline: - DB dumps (slovo): books-db (mariadb), mongo (shared), books-job-scheduler-mongo - DB dumps (bookva, added 2026-06-12): bookva-db (mariadb, тот же root pw что books-db), bookva-mongo (no-auth) -- ES snapshot via REST API (file repo `kreknin`) — **только slovo ES** -- rsync bind paths + dumps + `bookva-minio-data` (named volume, raw) + `/opt/books/` + `/etc/{ssh,hosts,cron.d}` + `/root/.ssh` → `vitya@kreknin:/volume1/NetBackup/books-vds//` +- ES snapshots via REST API (file repo `kreknin`): slovo `elasticsearch` + `bookva-es` (раздельные репо/каталоги) +- rsync bind paths + dumps + `bookva-minio-data` (named volume, raw) + `/usr/docker/bookva-es` (snapshot repo) + `/opt/books/` + `/etc/{ssh,hosts,cron.d}` + `/root/.ssh` → `vitya@kreknin:/volume1/NetBackup/books-vds//` - ntfy `BOOKS-VDS backup OK ` + email - Retention 7 daily snapshots -Live since 2026-05-25. **bookva tenant добавлен 2026-06-12** (db/mongo/minio verified на kreknin: bookva-mariadb 257M, bookva-mongo 3.2M, bookva-minio 1.4G). +Live since 2026-05-25. **bookva tenant добавлен 2026-06-12** (db/mongo/minio/es verified на kreknin: bookva-mariadb 257M, bookva-mongo 3.2M, bookva-minio 1.4G, bookva-es snapshot 801M). -**bookva-es НЕ снапшотится** (отдельный ES-контейнер, `path.repo` не сконфигурирован → REST-snapshot невозможен без recreate). Покрыт по факту: индексы `epz`(820604)/`products`(105922) **идентичны slovo ES**, который снапшотится. Полноценный bookva-es snapshot — `.tasks/bookva-es-snapshot-repo.md` (нужен Portainer stack edit + ES restart). Deploy script: `/opt/stacks/backup/run.sh` (== repo `scripts/books-vds-backup-daily-kreknin/run.sh`). +**bookva-es snapshot (added 2026-06-12):** Portainer stack 37 пересоздан с `path.repo=/snapshots` + bind `/usr/docker/bookva-es/snapshots` (uid 1000:0), repo `kreknin` зарегистрирован. **Gotcha:** оба ES-каталога называются `snapshots` → в rsync источник bookva-es = родительский `/usr/docker/bookva-es` (basename `bookva-es`), иначе слились бы в один dest/`snapshots/` и испортили оба репо. На kreknin: `snapshots/` (slovo) и `bookva-es/snapshots/` — раздельно. Deploy script: `/opt/stacks/backup/run.sh` (== repo `scripts/books-vds-backup-daily-kreknin/run.sh`). ## DNS diff --git a/scripts/books-vds-backup-daily-kreknin/run.sh b/scripts/books-vds-backup-daily-kreknin/run.sh index 1a07fa6..4bb2ab0 100644 --- a/scripts/books-vds-backup-daily-kreknin/run.sh +++ b/scripts/books-vds-backup-daily-kreknin/run.sh @@ -160,6 +160,34 @@ if [ $PRUNE_COUNT -gt 0 ]; then done fi +# === Step 2b: bookva-es snapshot (separate ES, own /snapshots repo, added 2026-06-12) === +echo "--- bookva-es snapshot $ES_SNAP in repo $ES_SNAPSHOT_REPO ---" +BSNAP_RESULT=$(docker exec bookva-es curl -sS -X PUT \ + "http://localhost:9200/_snapshot/$ES_SNAPSHOT_REPO/$ES_SNAP?wait_for_completion=true" \ + -H 'Content-Type: application/json') +echo "bookva-es snapshot result: $BSNAP_RESULT" +if ! echo "$BSNAP_RESULT" | grep -q '"state":"SUCCESS"'; then + echo "bookva-es snapshot did NOT report SUCCESS state — failing" + exit 3 +fi + +echo "--- prune bookva-es snapshots older than $RETENTION_DAYS ---" +BALL_SNAPS=$(docker exec bookva-es curl -sS "http://localhost:9200/_snapshot/$ES_SNAPSHOT_REPO/_all" \ + | grep -oE '"snapshot":"daily-[0-9-]+"' \ + | sed -E 's/.*"(daily-[0-9-]+)".*/\1/' \ + | sort) +BSNAP_COUNT=$(echo "$BALL_SNAPS" | wc -l) +BPRUNE_COUNT=$((BSNAP_COUNT - RETENTION_DAYS)) +if [ $BPRUNE_COUNT -gt 0 ]; then + echo "$BALL_SNAPS" | head -n "$BPRUNE_COUNT" | while read -r snap; do + [ -z "$snap" ] && continue + echo "deleting bookva-es snapshot: $snap" + docker exec bookva-es curl -sS -X DELETE \ + "http://localhost:9200/_snapshot/$ES_SNAPSHOT_REPO/$snap" || true + echo + done +fi + # === Step 3: rsync to kreknin === echo "--- rsync to $DEST_USER@$DEST_HOST:$DEST_PATH ---" ssh $SSH_OPTS "$DEST_USER@$DEST_HOST" "mkdir -p '$DEST_PATH'" @@ -173,6 +201,7 @@ rsync -aHh --info=stats2 --delete $LINK_DEST_ARG \ -e "ssh $SSH_OPTS" \ /opt/books \ /usr/docker/elasticsearch/snapshots \ + /usr/docker/bookva-es \ /usr/docker/minio/data \ /var/lib/docker/volumes/bookva-minio-data \ /usr/docker/traefik/letsencrypt \ @@ -220,7 +249,7 @@ Components: - /root/.ssh - DB dumps: books-db (mariadb), mongo (shared), books-job-scheduler-mongo, bookva-db (mariadb), bookva-mongo - bookva-minio: raw volume (bookva-minio-data) -- ES snapshot (slovo): $ES_SNAP [bookva-es: derivative index == slovo, snapshot pending Portainer path.repo] +- ES snapshots: $ES_SNAP (slovo elasticsearch + bookva-es, separate repos) Log: $LOG" email_send "[$HOST_LABEL] backup OK $TODAY" "$EMAIL_BODY"