Резервное копирование и восстановление
Что нужно сохранять
Заголовок раздела «Что нужно сохранять»| Данные | Где | Критичность |
|---|---|---|
| PostgreSQL | БД portal | Обязательно |
| Файлы библиотек | S3 bucket portal-files | Обязательно |
Лицензия (license.key, install.id) | PORTAL_DATA_DIR | Рекомендуется |
| Конфигурация | .env / portal.env / Helm values | Рекомендуется |
| Valkey | Кэш | Не обязательно (пересоздаётся) |
Как устроено (Docker)
Заголовок раздела «Как устроено (Docker)»| Компонент | Назначение |
|---|---|
| Служба portal-backup (вкл/выкл в админке) | Разрешает очередь и расписание; не выполняет бэкап сама. См. Службы |
| Контейнер backup-runner | Poll API каждые 30 с, pg_dump, sync S3, упаковка .tar.gz |
| Backup runner Online | Heartbeat runner’а за последние 2 мин (отдельно от «служба вкл») |
| Журнал в админке | Записи validate, backup, restore |
Runner поднимается вместе со стеком:
docker compose up -d # включает backup-runner (restart: unless-stopped)docker compose ps backup-runnerdocker compose logs -f backup-runnerСеть: runner обращается к API через host.docker.internal (Linux Docker Engine 20.10+ и Docker Desktop).
Каталог для бэкапов: важно
Заголовок раздела «Каталог для бэкапов: важно»Файлы попадают на хост только если каталог смонтирован в контейнер backup-runner.
В .env задают пару переменных:
| Переменная | Назначение |
|---|---|
PORTAL_BACKUP_HOST_DIR | Каталог на хосте (левая часть тома compose) |
PORTAL_BACKUP_MOUNT_PATH | Путь внутри контейнера (правая часть тома) |
В админке указывают ровно PORTAL_BACKUP_MOUNT_PATH (без завершающего /). Backend и runner отклоняют другой путь.
Примеры
Заголовок раздела «Примеры»Linux prod (каталог на сервере):
PORTAL_BACKUP_HOST_DIR=/var/backups/portalPORTAL_BACKUP_MOUNT_PATH=/var/backups/portalВ админке: /var/backups/portal.
Dev (каталог в репозитории):
# по умолчанию в docker-compose.yml, можно не задавать# PORTAL_BACKUP_HOST_DIR=./backups# PORTAL_BACKUP_MOUNT_PATH=/backupsВ админке: /backups. На хосте файлы в ./backups рядом с docker-compose.yml.
Dev на Mac (отдельная папка на диске):
PORTAL_BACKUP_HOST_DIR=/path/on/mac/BackupPortalPORTAL_BACKUP_MOUNT_PATH=/path/on/mac/BackupPortalОба значения — один и тот же абсолютный путь. После изменения .env:
docker compose up -d backup-runner backendВ админке: тот же путь, что PORTAL_BACKUP_MOUNT_PATH.
Частая ошибка: указать в админке путь Mac/Linux хоста, а в compose смонтирован другой каталог (например
./backups→/backups). Runner создаст файлы внутри контейнера, журнал покажет «Завершён», но на нужной папке хоста архива не будет.
Бэкап из админки
Заголовок раздела «Бэкап из админки»Страница: Службы → Резервное копирование → ⚙ Настройки (/services/portal-backup). Два аккордеона:
| Аккордеон | Содержимое |
|---|---|
| Резервное копирование | Путь, retention, проверка записи, создание копии, журнал, статус Runner online |
| Восстановление | Выбор успешной копии (restorable) и постановка restore в очередь |
Бейдж Runner online показывается на этой странице и в Обзор → Обслуживание, не в таблице «Службы».
- Откройте
/services/portal-backup - Укажите каталог (в Docker — ровно
PORTAL_BACKUP_MOUNT_PATH) и сохраните - Проверить запись (
validate— файла.tar.gzне создаёт) - Дождитесь Backup runner: Online
- Создать резервную копию — в журнале запись
backup, файлportal-backup-*.tar.gzв смонтированном каталоге - Расписание: на вкладке Службы у строки
portal-backupменю ⋮ → Расписание (после успешной проверки пути и online runner)
Уведомления об успешной постановке в очередь — тост. Ход выполнения — журнал (обновить, пагинация).
Статусы журнала
Заголовок раздела «Статусы журнала»| Статус | Значение |
|---|---|
| В очереди | Ждёт runner |
| Выполняется | Runner взял задание |
| Завершён | Успех (validate, backup или restore) |
| Ошибка | Runner сообщил /fail или задание зависло > 30 мин |
Быстрый бэкап (portal-cli на хосте)
Заголовок раздела «Быстрый бэкап (portal-cli на хосте)»Архивы пишутся напрямую на диск хоста (без очереди админки):
# Docker-установка — portal-cli на хосте из bundle./portal-cli/portal-cli backup --mode docker --output /mnt/nas/portal-backups
# Native./portal-cli/portal-cli backup --mode native --output /var/backups/portal
# Kubernetes./portal-cli/portal-cli backup --mode k8s --output /mnt/nas/portal-backupsПроверка каталога:
./portal-cli/portal-cli backup validate --path /mnt/nas/portal-backupsВосстановление из админки
Заголовок раздела «Восстановление из админки»Аккордеон Восстановление на /services/portal-backup:
- Список копий —
GET /api/v1/admin/backups/restorable(успешныеbackupс файлом на диске, до 50 шт.). - Выберите копию → подтвердите в модальном окне (деструктивная операция).
- Задание
restoreставится в очередь (POST /api/v1/admin/backups/{id}/restore);backup-runnerвыполняет восстановление.
Нужны: Runner online, нет активного задания backup/restore. На время операции портал недоступен.
API: Резервное копирование (API). Восстановление вручную на хосте:
./portal-cli/portal-cli restore --mode docker \ --file /mnt/nas/portal-backups/portal-backup-20260710-120000.tar.gz --yesПеременные окружения (CLI и runner)
Заголовок раздела «Переменные окружения (CLI и runner)»| Переменная | Назначение |
|---|---|
PORTAL_BACKUP_DIR | Каталог по умолчанию для portal-cli backup |
PORTAL_BACKUP_HOST_DIR | Каталог на хосте для тома backup-runner |
PORTAL_BACKUP_MOUNT_PATH | Путь внутри контейнера (= путь в админке) |
PORTAL_BACKUP_RETENTION_COUNT | Сколько последних .tar.gz хранить (default 7) |
PORTAL_BACKUP_RUNNER_TOKEN | Обязательный токен (X-Portal-Backup-Token) для internal API; без него запросы отклоняются |
PORTAL_BACKUP_API_URL | URL API для runner (в compose: http://host.docker.internal:…/api/v1) |
В Docker Compose backup-runner ходит в Docker через сервис docker-socket-proxy-backup (DOCKER_HOST=tcp://…:2375), а не монтирует /var/run/docker.sock напрямую. update-runner по-прежнему использует raw sock (нужен полный Engine API для compose upgrade); для продакшена предпочтителен host-native runner.
Ручной runner (если не используете compose):
./portal-cli/portal-cli backup-runnersudo systemctl enable --now portal-backup-runner # native Linuxdocker compose up -d backup-runner # dockerСетевое хранилище (SMB/NFS)
Заголовок раздела «Сетевое хранилище (SMB/NFS)»Portal не монтирует шары сам. Пример Linux:
sudo mkdir -p /mnt/nas/portal-backupssudo mount -t cifs //nas.corp/backups/portal /mnt/nas/portal-backups \ -o credentials=/etc/portal/nas.creds,uid=0,gid=0Смонтируйте NAS в PORTAL_BACKUP_HOST_DIR / укажите тот же путь в PORTAL_BACKUP_MOUNT_PATH и в админке.
Формат архива
Заголовок раздела «Формат архива»portal-backup-YYYYMMDD-HHMMSS.tar.gz├── manifest.json├── checksums.sha256├── postgres.dump├── s3/portal-files/...├── portal-data/...└── config/...Диагностика проблем
Заголовок раздела «Диагностика проблем»Журнал: «Выполняется» долго или навсегда
Заголовок раздела «Журнал: «Выполняется» долго или навсегда»-
Логи runner (главный источник):
Окно терминала docker compose logs -f backup-runner -
Запись в БД:
Окно терминала docker compose exec postgres psql -U portal -d portal -c \"SELECT id, kind, status, started_at, error_message FROM portal_backups ORDER BY created_at DESC LIMIT 5;" -
Задания в
running> 30 минут backend переводит в Ошибка при обновлении журнала или следующем poll runner’а. -
Ручной сброс зависшей записи:
UPDATE portal_backups SET status = 'failed',error_message = 'Сброс вручную',completed_at = NOW()WHERE id = '<uuid>' AND status = 'running';
«Завершён», но файла нет на диске
Заголовок раздела ««Завершён», но файла нет на диске»- Путь в админке ≠
PORTAL_BACKUP_MOUNT_PATH(см. раздел «Каталог для бэкапов»). - Проверьте том:
docker inspect portal-backup-runner-1 --format '{{json .Mounts}}'. - Убедитесь, что смотрите HOST_DIR на хосте, а не путь только внутри контейнера.
Backup runner Offline
Заголовок раздела «Backup runner Offline»docker compose ps backup-runnerdocker compose up -d backup-runnerdocker compose logs --tail 20 backup-runnerRunner должен отвечать на heartbeat (статус Online в админке в течение ~30 с).
Ручные команды (низкий уровень)
Заголовок раздела «Ручные команды (низкий уровень)»PostgreSQL
Заголовок раздела «PostgreSQL»# Dockerdocker compose exec postgres pg_dump -U portal -Fc portal > portal-backup.dump
# Nativepg_dump -h localhost -U portal -Fc portal > portal-backup.dumpmc mirror portal/portal-files ./backup/portal-files/Процедура обновления с backup
Заголовок раздела «Процедура обновления с backup»portal-cli backup --output <каталог>или кнопка в админкеportal-cli upgrade --mode <канал>- Проверка
/healthи/api/v1/system/version - При проблемах —
portal-cli restore --file <архив> --yes
RPO / RTO (ориентиры)
Заголовок раздела «RPO / RTO (ориентиры)»- RPO (Recovery Point Objective) — сколько данных можно потерять при сбое.
- RTO (Recovery Time Objective) — допустимое время простоя до восстановления.
| Профиль | RPO | RTO |
|---|---|---|
| Пилот | 24 ч | 4 ч |
| Production | 1 ч | 1 ч |
| Enterprise | 15 мин | 30 мин |
Настройте Расписание службы portal-backup в админке или systemd timer для portal-cli backup.