Бэкап: сервис backup в compose прода и тест-клона, .env.example
docker-compose.yml: сервис backup (образ из реестра, явный environment только с BACKUP_*, тома данных + backup-data), предупреждение про down -v. docker-compose.test.yml: тот же образ локальной сборкой, только локальный репозиторий, без расписания, BACKUP_VPS_HOST принудительно пуст. .env.example: новый блок BACKUP_* (пароль, расписание, хранение, сжатие, SFTP-пользователь fsbackup — системный backup в Debian/Ubuntu уже занят, ключ base64, адрес Pi для скриптов ПК); удалены BACKUP_VPS_KEY и BACKUP_KEEP_LOCAL/REMOTE. build-push: сообщения про третий образ (bake подхватывает сервис сам). #64 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jBxs9nBCk5nBdTLzcGz91
This commit is contained in:
+33
-9
@@ -90,16 +90,40 @@ IMAGE_TAG=latest
|
||||
#APP_MEM_LIMIT=512m
|
||||
#APP_CPUS=1.5
|
||||
|
||||
# ─── БЭКАП (оффсайт-копия на VPS; читает scripts/backup.sh на хосте Pi) ───────
|
||||
# Полный бэкап (БД + uploads + achievements) кладётся локально в backups/, и — если задан
|
||||
# BACKUP_VPS_HOST — копируется на VPS (Pi → VPS push, т.к. Pi за CGNAT). Пусто = только локально.
|
||||
# Ключ бэкапа — deploy/backup/id_backup (в git НЕ идёт); его pubkey → authorized_keys у backup@VPS.
|
||||
# ─── БЭКАПЫ (контейнер backup: restic; подробно — deploy/backup/README.md) ────
|
||||
# Снимки БД + uploads + achievements по расписанию: локально на Pi (том backup-data) и —
|
||||
# если задан BACKUP_VPS_HOST — на VPS по SFTP. Шифрование, дедупликация, сжатие — restic.
|
||||
#
|
||||
# Пароль шифрования репозиториев. ПОТЕРЯЕТЕ ПАРОЛЬ — НИ ОДИН БЭКАП НЕ ПРОЧИТАТЬ.
|
||||
# Сохраните его в менеджер паролей. Пусто = бэкапы отключены. Без символа '$'.
|
||||
# Сгенерировать: python -c "import secrets;print(secrets.token_urlsafe(32))"
|
||||
BACKUP_PASSWORD=
|
||||
# Когда делать бэкап и проверку данных (cron: минута час день месяц день_недели; TZ ниже).
|
||||
BACKUP_SCHEDULE="0 4 * * *"
|
||||
BACKUP_VERIFY_SCHEDULE="30 5 * * 0"
|
||||
BACKUP_TZ=Europe/Moscow
|
||||
# Сколько хранить: последний снимок каждого дня / недели / месяца.
|
||||
# Именованные снимки (fs-backup run --tag …) и страховочные pre-restore не удаляются.
|
||||
BACKUP_KEEP_DAILY=14
|
||||
BACKUP_KEEP_WEEKLY=8
|
||||
BACKUP_KEEP_MONTHLY=12
|
||||
# Сжатие restic: auto (быстрее) | max (плотнее) | off.
|
||||
BACKUP_COMPRESSION=max
|
||||
# Контейнер помечается unhealthy, если последний успешный бэкап старше стольких часов.
|
||||
BACKUP_MAX_AGE_HOURS=30
|
||||
# Оффсайт-копия на VPS (SFTP). Пусто = только локальная копия на Pi.
|
||||
BACKUP_VPS_HOST=
|
||||
BACKUP_VPS_USER=backup
|
||||
BACKUP_VPS_DIR=/srv/fs-backups
|
||||
BACKUP_VPS_KEY=deploy/backup/id_backup
|
||||
BACKUP_KEEP_LOCAL=14
|
||||
BACKUP_KEEP_REMOTE=30
|
||||
BACKUP_VPS_USER=fsbackup
|
||||
BACKUP_VPS_PORT=22
|
||||
BACKUP_VPS_DIR=/srv/fs-backups/restic
|
||||
# Приватный SSH-ключ для VPS в base64 одной строкой (как TUNNEL_KEY_B64). На ПК ключ лежит
|
||||
# в deploy/backup/id_backup (в git НЕ идёт), pubkey — в authorized_keys у fsbackup@VPS.
|
||||
# PowerShell: [Convert]::ToBase64String([IO.File]::ReadAllBytes((Resolve-Path "deploy\backup\id_backup")))
|
||||
BACKUP_SSH_KEY_B64=
|
||||
# Только для ПК (scripts/fs-backup.ps1 / .sh): как зайти на Pi по SSH и где там лежит
|
||||
# docker-compose.yml прода.
|
||||
BACKUP_PI_SSH=pi@192.168.1.10
|
||||
BACKUP_PI_DIR=~/forbidden-stars
|
||||
|
||||
# ─── ПРОЧЕЕ ───────────────────────────────────────────────────────────────────
|
||||
# Часовой пояс приложения (фикс. смещение в часах; МСК = 3)
|
||||
|
||||
@@ -56,7 +56,31 @@ services:
|
||||
- ./deploy/tunnel/id_tunnel:/key/id_tunnel:ro
|
||||
mem_limit: 64m
|
||||
|
||||
# Бэкапы тест-клона: тот же образ, что у прода (сборка локально), но ТОЛЬКО локальный
|
||||
# репозиторий и без расписания. BACKUP_VPS_HOST принудительно пуст — тестовые данные
|
||||
# никогда не попадут в прод-репозиторий на VPS. Учебное восстановление:
|
||||
# .\scripts\fs-backup.ps1 restore-test -File backups\fs_....tar
|
||||
backup:
|
||||
build: ./deploy/backup
|
||||
image: forbidden-stars-backup:test
|
||||
restart: "no"
|
||||
environment:
|
||||
BACKUP_PASSWORD: ${BACKUP_PASSWORD:-test-contour-only}
|
||||
BACKUP_HOSTNAME: fs-test
|
||||
BACKUP_SCHEDULE: ""
|
||||
BACKUP_VERIFY_SCHEDULE: ""
|
||||
BACKUP_VPS_HOST: ""
|
||||
BACKUP_COMPRESSION: ${BACKUP_COMPRESSION:-max}
|
||||
TZ: ${BACKUP_TZ:-Europe/Moscow}
|
||||
volumes:
|
||||
- db-data-test:/fs-db
|
||||
- uploads-data-test:/fs/uploads
|
||||
- achievements-data-test:/fs/achievements
|
||||
- backup-data-test:/backup
|
||||
mem_limit: 384m
|
||||
|
||||
volumes:
|
||||
db-data-test:
|
||||
uploads-data-test:
|
||||
achievements-data-test:
|
||||
backup-data-test:
|
||||
|
||||
+46
-2
@@ -6,9 +6,13 @@
|
||||
# (scripts/build-push.*) — на Pi он не используется.
|
||||
#
|
||||
# Запуск/обновление: docker compose up -d (сам тянет свежие образы)
|
||||
# Логи: docker compose logs -f app (или: ... tunnel)
|
||||
# Логи: docker compose logs -f app (или: ... tunnel / backup)
|
||||
# Остановка: docker compose down (данные в томах сохраняются)
|
||||
# Бэкап/restore: scripts/backup.sh / scripts/restore.sh
|
||||
# Бэкапы: docker compose exec backup fs-backup status (help — все команды)
|
||||
# инструкция: deploy/backup/README.md
|
||||
#
|
||||
# НИКОГДА не выполняйте на проде `docker compose down -v`: флаг -v удаляет тома — и данные
|
||||
# приложения, и локальный репозиторий бэкапов (останется только копия на VPS).
|
||||
#
|
||||
# Контейнер ВСЕГДА production: APP_ENV форсится здесь и игнорирует значение из .env.
|
||||
# Порты на хост НЕ публикуются — наружу приложение выставляет только сервис tunnel
|
||||
@@ -69,7 +73,47 @@ services:
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
# Бэкапы (restic): снимки по расписанию в локальный репозиторий (том backup-data) и на VPS
|
||||
# (SFTP, если задан BACKUP_VPS_HOST). От app не зависит и app не мешает. Переменные —
|
||||
# только BACKUP_* (секреты приложения сюда не передаются). Всё про настройку и
|
||||
# восстановление — deploy/backup/README.md.
|
||||
backup:
|
||||
build: ./deploy/backup
|
||||
image: ${IMAGE_REGISTRY:-gitea.arseniev.info/notbigghost}/forbidden-stars-backup:${IMAGE_TAG:-latest}
|
||||
pull_policy: always
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
BACKUP_PASSWORD: ${BACKUP_PASSWORD:-} # пароль шифрования; пусто = бэкапы отключены
|
||||
BACKUP_HOSTNAME: fs-prod # имя хоста в снимках (у тест-клона — fs-test)
|
||||
BACKUP_SCHEDULE: ${BACKUP_SCHEDULE:-0 4 * * *}
|
||||
BACKUP_VERIFY_SCHEDULE: ${BACKUP_VERIFY_SCHEDULE:-30 5 * * 0}
|
||||
BACKUP_KEEP_DAILY: ${BACKUP_KEEP_DAILY:-14}
|
||||
BACKUP_KEEP_WEEKLY: ${BACKUP_KEEP_WEEKLY:-8}
|
||||
BACKUP_KEEP_MONTHLY: ${BACKUP_KEEP_MONTHLY:-12}
|
||||
BACKUP_COMPRESSION: ${BACKUP_COMPRESSION:-max}
|
||||
BACKUP_MAX_AGE_HOURS: ${BACKUP_MAX_AGE_HOURS:-30}
|
||||
BACKUP_VPS_HOST: ${BACKUP_VPS_HOST:-}
|
||||
BACKUP_VPS_USER: ${BACKUP_VPS_USER:-fsbackup}
|
||||
BACKUP_VPS_PORT: ${BACKUP_VPS_PORT:-22}
|
||||
BACKUP_VPS_DIR: ${BACKUP_VPS_DIR:-/srv/fs-backups/restic}
|
||||
BACKUP_SSH_KEY_B64: ${BACKUP_SSH_KEY_B64:-}
|
||||
TZ: ${BACKUP_TZ:-Europe/Moscow}
|
||||
volumes:
|
||||
- db-data:/fs-db # живая БД (снимается консистентно)
|
||||
- uploads-data:/fs/uploads
|
||||
- achievements-data:/fs/achievements
|
||||
- backup-data:/backup # локальный репозиторий restic + состояние
|
||||
mem_limit: ${BACKUP_MEM_LIMIT:-384m}
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
uploads-data:
|
||||
achievements-data:
|
||||
backup-data:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Build prod images (app + tunnel) for linux/arm64 (Raspberry Pi) and push to the registry.
|
||||
# Build prod images (app + tunnel + backup) for linux/arm64 (Raspberry Pi) and push to the registry.
|
||||
# Run on the DEV machine with Docker Desktop / buildx. Registry and tag come from the root
|
||||
# .env (IMAGE_REGISTRY / IMAGE_TAG) - the same values docker-compose.yml uses.
|
||||
# Log in to the registry once before running: docker login gitea.arseniev.info
|
||||
@@ -16,7 +16,7 @@ if ($LASTEXITCODE -ne 0) {
|
||||
# arm64 emulation on an x86 host (usually already present in Docker Desktop; idempotent).
|
||||
docker run --privileged --rm tonistiigi/binfmt --install arm64 | Out-Null
|
||||
|
||||
Write-Host "Building app+tunnel for linux/arm64 and pushing to the registry..." -ForegroundColor Green
|
||||
Write-Host "Building app+tunnel+backup for linux/arm64 and pushing to the registry..." -ForegroundColor Green
|
||||
docker buildx bake -f docker-compose.yml --builder fsbuilder --set "*.platform=linux/arm64" --push
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Build/push FAILED (exit $LASTEXITCODE)." -ForegroundColor Red
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Сборка прод-образов (app + tunnel) под linux/arm64 для Raspberry Pi и пуш в реестр.
|
||||
# Сборка прод-образов (app + tunnel + backup) под linux/arm64 для Raspberry Pi и пуш в реестр.
|
||||
# Запускается на машине РАЗРАБОТКИ с Docker Desktop/buildx (не на Pi).
|
||||
# Реестр и тег берутся из корневого .env (IMAGE_REGISTRY / IMAGE_TAG) — те же, что в
|
||||
# docker-compose.yml. Перед запуском один раз залогиниться в реестр:
|
||||
@@ -17,7 +17,7 @@ fi
|
||||
# Эмуляция arm64 на x86-хосте (в Docker Desktop обычно уже стоит; команда идемпотентна).
|
||||
docker run --privileged --rm tonistiigi/binfmt --install arm64 >/dev/null
|
||||
|
||||
echo "[build-push] Сборка app+tunnel под linux/arm64 и пуш в реестр…"
|
||||
echo "[build-push] Сборка app+tunnel+backup под linux/arm64 и пуш в реестр…"
|
||||
# bake читает docker-compose.yml: контексты build: и теги image: (с подстановкой из .env).
|
||||
docker buildx bake -f docker-compose.yml --builder fsbuilder --set "*.platform=linux/arm64" --push
|
||||
|
||||
|
||||
Reference in New Issue
Block a user