Один бинарник backupctl: - server: API для агентов и restore, веб-морда (один админ), SQLite, ретеншн GFS, heavy-части, уведомления ntfy, раздача agent.sh/restore.sh; - backup/plan: сбор по каталогу категорий (files/systemd/xui/compose), горячие дампы Postgres/Mongo/MySQL, снимок x-ui.db, docker-тома, digest образов, проверка crontab, потоковая отправка tar.zst; - restore: провижининг на основе vps_installer с теми же версиями пакетов, recipes 3x-ui/nebula/sing-box нужных версий, восстановление compose с заливкой дампов и закреплением образов по digest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.1 KiB
6.1 KiB
Устройство backup-master
Компоненты
Старый сервер Сервер бэкапов Новый сервер
backupctl backup ──PUT части──► backupctl server ◄── backupctl restore
(systemd timer) SQLite + файлы, веб-морда provision.sh → recipes → распаковка → сервисы
ретеншн, ntfy
| Пакет | Назначение |
|---|---|
internal/manifest |
формат манифеста бэкапа (общий для всех) |
internal/catalog |
категории бэкапа: встроенный default.yaml + переопределения клиента |
internal/archive |
tar (PAX) + zstd: запись, распаковка, исключения, владельцы по имени |
internal/api |
протокол и HTTP-клиент |
internal/agent |
сбор: files / systemd / xui / compose, дампы, проверка crontab, отправка |
internal/restore |
восстановление: provision.sh, recipes бинарников, compose, порядок категорий |
internal/server |
API, веб-морда, ретеншн, уведомления |
Формат архива
Каждая часть — tar.zst. В main первой записью идёт manifest.json. Пути внутри архива:
<cat>/files/<абсолютный путь>— восстанавливается в/;<cat>/dumps/<файл>— дампы БД и снимок x-ui.db;<cat>/volumes/<том>/…— именованные docker-тома;<cat>/bin/<абсолютный путь>— fallback-копии бинарников.
Heavy-часть называется именем категории и устроена так же. Main без неё самодостаточен.
Протокол
| Метод | Токен | Назначение |
|---|---|---|
GET /api/v1/agent/config |
агент | домен, переопределения каталога, пора ли слать heavy |
POST /api/v1/backups |
агент | манифест → id |
PUT /api/v1/backups/{id}/parts/{name} |
агент | потоковая загрузка части |
POST /api/v1/backups/{id}/complete |
агент | sha256/размеры частей + предупреждения архивации |
POST /api/v1/backups/{id}/fail |
агент | ошибка |
GET /api/v1/restore/manifest[?backup=] |
restore | манифест и доступные части |
GET /api/v1/restore/{id}/parts/{name} |
restore | скачивание (Range — докачка) |
Агентский токен даёт только запись: если клиента взломают, злоумышленник не сможет прочитать или удалить его историю. Restore-токен выпускается в морде на 24 часа и даёт только чтение бэкапов одного клиента. В БД хранятся только sha256 токенов.
Агент архивирует часть прямо в тело PUT (io.Pipe), временный архив на диске не создаётся. Дампы БД снимаются до архивации. Поэтому в Stoat порядок «сначала mongodump, потом файлы MinIO» соблюдается сам собой: файлы, загруженные во время бэкапа, станут лишними объектами без ссылок, но ссылок на отсутствующие файлы не появится.
Compose
- Проекты берутся из
docker compose ls -a, к ним добавляются явныеdirиз каталога. Сервисы, bind-mounts и тома — изdocker compose config --format json. - БД определяются по образу. Если контейнер запущен, делается дамп через
docker exec: учётные данные берутся из окружения контейнера, а каталог данных исключается. Если остановлен — каталог данных копируется как есть (он консистентен). - Данные
rabbitmqи сервисов изskip_servicesне бэкапятся. - Записываются digest запущенных образов. При восстановлении создаётся
compose.restore.ymlсimage: repo@sha256:…, потому чтоlatestна новом сервере дал бы другую Mongo/MinIO. - Отсутствующие external-сети создаются пустыми. Так stoat-mbot поднимается без psiphon.
- Порядок восстановления:
pull→build→create→ для каждой БДup -d <db>→ ожидание TCP-готовности → заливка дампа →up -d.
Версии
| Что | Как записывается | Как восстанавливается |
|---|---|---|
| apt-пакеты (caddy, telegraf, docker-ce, docker-compose-plugin) | dpkg-query |
provision.sh ставит pkg=version, если версия есть в репозитории |
| 3x-ui, nebula, sing-box-extended | version_cmd |
recipes в internal/restore/recipes.go: release-архивы нужного тега; при неудаче — копия из bin/ |
| образы compose | digest | compose.restore.yml |
Расширение
- Новая категория — запись в
default.yamlили в YAML клиента в морде. - Новый способ установки бинарника — функция в
recipes, имя указывается в полеinstallкатегории. - Новый тип БД в compose —
dbKind/dumpCmdsвinternal/agent/compose.goиdbReady/dbRestoreвinternal/restore/compose.go.