Перейти к содержимому

Резервное копирование и восстановление

ДанныеГдеКритичность
PostgreSQLБД portalОбязательно
Файлы библиотекS3 bucket portal-filesОбязательно
Лицензия (license.key, install.id)PORTAL_DATA_DIRРекомендуется
Конфигурация.env / portal.env / Helm valuesРекомендуется
ValkeyКэшНе обязательно (пересоздаётся)
КомпонентНазначение
Служба portal-backup (вкл/выкл в админке)Разрешает очередь и расписание; не выполняет бэкап сама. См. Службы
Контейнер backup-runnerPoll API каждые 30 с, pg_dump, sync S3, упаковка .tar.gz
Backup runner OnlineHeartbeat runner’а за последние 2 мин (отдельно от «служба вкл»)
Журнал в админкеЗаписи validate, backup, restore

Runner поднимается вместе со стеком:

Окно терминала
docker compose up -d # включает backup-runner (restart: unless-stopped)
docker compose ps backup-runner
docker 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/portal
PORTAL_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/BackupPortal
PORTAL_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 показывается на этой странице и в Обзор → Обслуживание, не в таблице «Службы».

  1. Откройте /services/portal-backup
  2. Укажите каталог (в Docker — ровно PORTAL_BACKUP_MOUNT_PATH) и сохраните
  3. Проверить запись (validate — файла .tar.gz не создаёт)
  4. Дождитесь Backup runner: Online
  5. Создать резервную копию — в журнале запись backup, файл portal-backup-*.tar.gz в смонтированном каталоге
  6. Расписание: на вкладке Службы у строки portal-backup меню ⋮ → Расписание (после успешной проверки пути и online runner)

Уведомления об успешной постановке в очередь — тост. Ход выполнения — журнал (обновить, пагинация).

СтатусЗначение
В очередиЖдёт runner
ВыполняетсяRunner взял задание
ЗавершёнУспех (validate, backup или restore)
ОшибкаRunner сообщил /fail или задание зависло > 30 мин

Архивы пишутся напрямую на диск хоста (без очереди админки):

Окно терминала
# 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:

  1. Список копий — GET /api/v1/admin/backups/restorable (успешные backup с файлом на диске, до 50 шт.).
  2. Выберите копию → подтвердите в модальном окне (деструктивная операция).
  3. Задание 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
ПеременнаяНазначение
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_URLURL 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-runner
sudo systemctl enable --now portal-backup-runner # native Linux
docker compose up -d backup-runner # docker

Portal не монтирует шары сам. Пример Linux:

Окно терминала
sudo mkdir -p /mnt/nas/portal-backups
sudo 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/...
  1. Логи runner (главный источник):

    Окно терминала
    docker compose logs -f backup-runner
  2. Запись в БД:

    Окно терминала
    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;"
  3. Задания в running > 30 минут backend переводит в Ошибка при обновлении журнала или следующем poll runner’а.

  4. Ручной сброс зависшей записи:

    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 на хосте, а не путь только внутри контейнера.
Окно терминала
docker compose ps backup-runner
docker compose up -d backup-runner
docker compose logs --tail 20 backup-runner

Runner должен отвечать на heartbeat (статус Online в админке в течение ~30 с).

Окно терминала
# Docker
docker compose exec postgres pg_dump -U portal -Fc portal > portal-backup.dump
# Native
pg_dump -h localhost -U portal -Fc portal > portal-backup.dump
Окно терминала
mc mirror portal/portal-files ./backup/portal-files/
  1. portal-cli backup --output <каталог> или кнопка в админке
  2. portal-cli upgrade --mode <канал>
  3. Проверка /health и /api/v1/system/version
  4. При проблемах — portal-cli restore --file <архив> --yes
  • RPO (Recovery Point Objective) — сколько данных можно потерять при сбое.
  • RTO (Recovery Time Objective) — допустимое время простоя до восстановления.
ПрофильRPORTO
Пилот24 ч4 ч
Production1 ч1 ч
Enterprise15 мин30 мин

Настройте Расписание службы portal-backup в админке или systemd timer для portal-cli backup.