backup-master: сервер бэкапов, агент и восстановление VPS
Один бинарник 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>
This commit is contained in:
commit
1d44d067e9
53 files changed
+7278
No files matched your search
@@ -0,0 +1,70 @@
|
||||
# Устройство 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`.
|
||||
Reference in new issue
Block a user