Перейти к содержанию

Бэкап RAG-platform — runbook (RAG-05)

Цель: ежедневный консистентный бэкап всего RAG-стека на ragserver: Postgres (метаданные OpenWebUI), Qdrant (векторные эмбеддинги), OpenWebUI data (файлы/аттачменты/uploads), .env, docker-compose.yml.

Если ragserver упадёт — все Knowledge collections, файлы, эмбеддинги можно поднять на новом железе за ~30 минут.

Технология: - Postgres: pg_dump --format=custom — консистентный дамп даже при живой БД - Qdrant: POST /collections/{col}/snapshots — атомарный snapshot всей коллекции - OpenWebUI data: обычный tar -czf (файлы читаются, не пишутся во время бэкапа обычно) - Всё вместе → tar → GPG AES-256 → ретеншн 14 дней

Итоговый архив ~сотни MB (в зависимости от объёма knowledge). GPG-пароль тот же что для Vaultwarden и AmneziaWG.


Шаг 1 · Подготовить окружение на ragserver

# На ragserver (192.168.1.200), от oswold:
mkdir -p /home/oswold/backups/rag-platform
chmod 700 /home/oswold/backups /home/oswold/backups/rag-platform

# GPG passfile — тот же пароль что в /root/.vw_backup_pass на VPS
# Скопируй значение с VPS (SSH туда, cat /root/.vw_backup_pass, сохрани сюда):
touch /home/oswold/.rag_backup_pass
chmod 600 /home/oswold/.rag_backup_pass
# Вставь пароль:
echo 'PASTE_THE_SAME_GPG_PASSPHRASE_HERE' > /home/oswold/.rag_backup_pass

Проверка что gnupg установлен:

which gpg || sudo apt install -y gnupg


Шаг 2 · Установить скрипт

# На ragserver:
mkdir -p /opt/rag-platform/backups
cd /opt/rag-platform/backups

# Скачать (репо приватный — либо через github CLI, либо scp с локали):
scp <твоя_локальная_машина>:/tmp/alatyr-infra-kb/skeletons/backup-rag-platform.sh ./
# Или после того как ты клонируешь alatyr-infra-kb на ragserver:
#   cp /path/to/alatyr-infra-kb/skeletons/backup-rag-platform.sh ./

chmod 700 backup-rag-platform.sh

⚠️ Внутри скрипта строка sudo tar -czf ... openwebui требует sudo без пароля.

Вариант A — добавить в sudoers для oswold (безопаснее, ограничить только этой командой):

sudo visudo -f /etc/sudoers.d/rag-backup
Внутри:
oswold ALL=(root) NOPASSWD: /bin/tar -czf /tmp/rag_staging_*/openwebui-data.tar.gz -C /opt/rag-platform/data openwebui
oswold ALL=(root) NOPASSWD: /bin/cp /opt/rag-platform/.env /tmp/rag_staging_*/env
oswold ALL=(root) NOPASSWD: /bin/cp /opt/rag-platform/docker-compose.yml /tmp/rag_staging_*/docker-compose.yml
oswold ALL=(root) NOPASSWD: /bin/chown oswold\:oswold /tmp/rag_staging_*/env /tmp/rag_staging_*/docker-compose.yml

Вариант B — прогонять cron от root вместо oswold (проще, но root-cron):

sudo crontab -e
# Добавить: 0 4 * * * /opt/rag-platform/backups/backup-rag-platform.sh

Мы выбираем вариант B для простоты (cron уже под root на VPS для Vaultwarden — тот же паттерн).


Шаг 3 · Первый ручной прогон

# От root:
sudo /opt/rag-platform/backups/backup-rag-platform.sh
sudo tail -50 /home/oswold/backups/rag-backup.log

Ожидание в логе:

[2026-08-08 04:00:12] [1/5] Postgres dump
[2026-08-08 04:00:14]   Postgres dump: 1234567 байт
[2026-08-08 04:00:14] [2/5] Qdrant snapshots
[2026-08-08 04:00:15]   Snapshot коллекции: alatyr-infra-kb
[2026-08-08 04:00:18]   Snapshot коллекции: personal
[2026-08-08 04:00:20] [3/5] OpenWebUI data
[2026-08-08 04:00:35]   OpenWebUI data: 234567890 байт
[2026-08-08 04:00:36] [4/5] Конфиги
[2026-08-08 04:00:36] [5/5] Архивирую и шифрую
[2026-08-08 04:01:12]   Зашифрованный: .../rag-backup-*.tar.gz.gpg (234567891 байт)
[2026-08-08 04:01:12] OK: 1 архивов, суммарно 224M

Быстрая проверка:

sudo ls -lh /home/oswold/backups/rag-platform/
sudo file /home/oswold/backups/rag-platform/*.gpg
# ожидание: GPG symmetrically encrypted data (AES256)


Шаг 4 · Cron

sudo crontab -e

Добавить:

# Бэкап RAG-platform (RAG-05). 04:00 MSK — после Vaultwarden/AmneziaWG
0 4 * * * /opt/rag-platform/backups/backup-rag-platform.sh >/dev/null 2>&1

Проверить:

sudo crontab -l | grep rag-backup


Шаг 5 · Test restore (обязательно, разово)

Проверить что бэкап реально можно раскатать.

# На тестовой машине или /tmp:
mkdir -p /tmp/rag-restore-test && cd /tmp/rag-restore-test
sudo cp /home/oswold/backups/rag-platform/rag-backup-*.gpg ./

# 1. GPG-расшифровка
sudo gpg --decrypt --passphrase-file /home/oswold/.rag_backup_pass \
    --batch --output rag-restore.tar.gz \
    rag-backup-*.gpg

# 2. Распаковать
sudo tar -tzf rag-restore.tar.gz | head -20
# Ожидание: postgres-*.dump, qdrant/, openwebui-data.tar.gz, env, docker-compose.yml, metadata.txt

sudo tar -xzf rag-restore.tar.gz -C ./
ls -la

# 3. Postgres dump — проверка структуры (не восстанавливаем в БД)
sudo pg_restore --list postgres-*.dump | head -30
# Ожидание: список таблиц OpenWebUI (auth, chat, document, file, ...)

# 4. Qdrant snapshot — проверка что файл валидный tar
sudo tar -tzf qdrant/*__*.snapshot 2>&1 | head -5 || \
    sudo file qdrant/*__*
# Snapshot Qdrant — это tar внутри (Qdrant формат), проверить размер >0

sudo rm -rf /tmp/rag-restore-test

Если всё расшифровалось и структуры целые → ✅ бэкап рабочий.


Как восстановить RAG-platform из бэкапа (disaster recovery)

Сценарий: новый ragserver или severe corruption.

  1. Установить Docker + Docker Compose + gnupg.
  2. Расшифровать самый свежий бэкап:
    gpg --decrypt --output rag-restore.tar.gz rag-backup-*.gpg
    mkdir /opt/rag-platform
    tar -xzf rag-restore.tar.gz -C /opt/rag-platform/restore/
    
  3. Восстановить .env и docker-compose.yml:
    cp restore/env /opt/rag-platform/.env
    cp restore/docker-compose.yml /opt/rag-platform/
    chmod 600 /opt/rag-platform/.env
    
  4. Восстановить OpenWebUI data:
    mkdir -p /opt/rag-platform/data
    tar -xzf restore/openwebui-data.tar.gz -C /opt/rag-platform/data/
    
  5. Стартануть Postgres и Qdrant (без OpenWebUI пока):
    cd /opt/rag-platform
    docker compose up -d rag-postgres rag-qdrant
    sleep 15
    
  6. Восстановить Postgres:
    POSTGRES_USER=$(grep POSTGRES_USER .env | cut -d= -f2)
    POSTGRES_DB=$(grep POSTGRES_DB .env | cut -d= -f2)
    docker exec -i rag-postgres pg_restore -U $POSTGRES_USER -d $POSTGRES_DB \
        --clean --if-exists < restore/postgres-*.dump
    
  7. Восстановить Qdrant snapshots (для каждой коллекции):
    QDRANT_KEY=$(grep QDRANT_API_KEY .env | cut -d= -f2)
    for snap in restore/qdrant/*; do
        col=$(basename "$snap" | cut -d_ -f1)
        # Upload snapshot в Qdrant
        curl -X POST -H "api-key: $QDRANT_KEY" \
            "http://localhost:6333/collections/${col}/snapshots/upload" \
            -F "snapshot=@$snap"
        # Восстановить из snapshot
        curl -X PUT -H "api-key: $QDRANT_KEY" \
            "http://localhost:6333/collections/${col}/snapshots/recover" \
            -d "{\"location\": \"file://$snap\"}"
    done
    
  8. Стартовать OpenWebUI:
    docker compose up -d
    docker compose logs -f rag-openwebui
    
  9. Проверить https://rag.alatyr-service.ru — все коллекции и файлы на месте.

Ожидаемое время disaster recovery: 30-45 минут на всё.


Off-site sync?

RAG-платформа сама уже "off-site" от VPS. Но если хочется дублирования на VPS (или на облачное хранилище) — открытый вопрос:

  • Архивы могут быть сотни MB — 1 GB. VPS Hostkey vm-mini имеет ограниченное место.
  • Если решим — тот же паттерн что offsite.sh, но в обратную сторону (VPS pull-ит).
  • Альтернатива: Yandex S3 (glacier-tier, ~$5/мес за 100GB), rclone.

Пока — retention 14 дней локально на ragserver достаточно. Проработать этот вопрос отдельной задачей когда бэкапы стабилизируются.


Мониторинг

# Через 2 дня проверить логи:
sudo tail -100 /home/oswold/backups/rag-backup.log
# Ожидание: 2 записи "OK" с ростом счётчика архивов

# Размер бэкапов:
sudo du -sh /home/oswold/backups/rag-platform/

Uptime Kuma (задача 28) — push-monitor из скрипта после успеха.


Диагностика

Симптом Причина Действия
pg_dump: connection refused Postgres контейнер упал docker ps, docker logs rag-postgres
Qdrant snapshot 500 Qdrant OOM или диск полный docker stats rag-qdrant, df -h /opt/rag-platform
Архивы становятся всё больше Уплотнение не работает Проверить RAG_EMBEDDING_MODEL — не сменилась ли на большую
gpg: no passphrase given passfile отсутствует Пересоздать /home/oswold/.rag_backup_pass

Автор: агент, 08.08.2026