#!/bin/bash # # Скрипт бэкапа Gitea LXC контейнера с Proxmox хоста # Запускать НА PROXMOX хосте # # Выполняет: # 1. Бэкап на уровне приложения (gitea dump + pg_dump) внутри LXC # 2. vzdump - полный бэкап контейнера (опционально) # set -e # ============================================ # НАСТРОЙКИ # ============================================ # ID LXC контейнера с Gitea LXC_ID="${LXC_ID:-300}" # Директория для хранения бэкапов на Proxmox BACKUP_STORAGE="${BACKUP_STORAGE:-/var/lib/vz/dump}" # Делать ли полный vzdump контейнера (занимает много места) DO_VZDUMP="${DO_VZDUMP:-false}" # Сжатие для vzdump: zstd, gzip, lzo, none VZDUMP_COMPRESS="${VZDUMP_COMPRESS:-zstd}" # Сколько бэкапов хранить KEEP_BACKUPS="${KEEP_BACKUPS:-7}" # Сколько vzdump хранить (они большие!) KEEP_VZDUMP="${KEEP_VZDUMP:-3}" # Удалённый сервер для копирования (опционально) REMOTE_BACKUP="${REMOTE_BACKUP:-}" # user@host:/path # ============================================ # ФУНКЦИИ # ============================================ log() { echo -e "\033[1;34m[$(date '+%Y-%m-%d %H:%M:%S')]\033[0m $1" } warn() { echo -e "\033[1;33m[WARN]\033[0m $1" } error() { echo -e "\033[1;31m[ERROR]\033[0m $1" >&2 exit 1 } # ============================================ # ПРОВЕРКИ # ============================================ if ! command -v pct &>/dev/null; then error "Этот скрипт должен запускаться на Proxmox хосте" fi if ! pct status "$LXC_ID" &>/dev/null; then error "LXC контейнер $LXC_ID не найден" fi LXC_STATUS=$(pct status "$LXC_ID" | awk '{print $2}') if [ "$LXC_STATUS" != "running" ]; then error "LXC контейнер $LXC_ID не запущен (статус: $LXC_STATUS)" fi mkdir -p "$BACKUP_STORAGE" # ============================================ # ПЕРЕМЕННЫЕ # ============================================ TIMESTAMP=$(date +%Y%m%d-%H%M%S) GITEA_BACKUP_DIR="/var/backups/gitea" log "==========================================" log " Бэкап Gitea LXC (ID: $LXC_ID)" log "==========================================" log "" # ============================================ # ШАГ 1: БЭКАП НА УРОВНЕ ПРИЛОЖЕНИЯ # ============================================ log "Запуск бэкапа Gitea внутри LXC..." # Копируем скрипт бэкапа в контейнер SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" if [ -f "$SCRIPT_DIR/backup-gitea-lxc.sh" ]; then pct push "$LXC_ID" "$SCRIPT_DIR/backup-gitea-lxc.sh" /root/backup-gitea-lxc.sh pct exec "$LXC_ID" -- chmod +x /root/backup-gitea-lxc.sh fi # Запускаем бэкап внутри контейнера BACKUP_OUTPUT=$(pct exec "$LXC_ID" -- bash -c "KEEP_BACKUPS=$KEEP_BACKUPS /root/backup-gitea-lxc.sh" 2>&1) || { echo "$BACKUP_OUTPUT" error "Бэкап внутри LXC завершился с ошибкой" } echo "$BACKUP_OUTPUT" # Получаем путь к созданному архиву (последняя строка вывода) LXC_BACKUP_FILE=$(echo "$BACKUP_OUTPUT" | tail -1) if [ -z "$LXC_BACKUP_FILE" ] || ! pct exec "$LXC_ID" -- test -f "$LXC_BACKUP_FILE"; then # Ищем последний бэкап LXC_BACKUP_FILE=$(pct exec "$LXC_ID" -- ls -t "$GITEA_BACKUP_DIR"/gitea-backup-*.tar.gz 2>/dev/null | head -1) fi if [ -n "$LXC_BACKUP_FILE" ]; then log "Копирование бэкапа из LXC..." BACKUP_NAME=$(basename "$LXC_BACKUP_FILE") pct pull "$LXC_ID" "$LXC_BACKUP_FILE" "$BACKUP_STORAGE/$BACKUP_NAME" log " ✓ $BACKUP_STORAGE/$BACKUP_NAME" # Удаляем архив из LXC (хранятся только на Proxmox) pct exec "$LXC_ID" -- rm -f "$LXC_BACKUP_FILE" log " ✓ Удалён из LXC (хранится только на Proxmox)" else warn "Не удалось найти архив бэкапа в LXC" fi # ============================================ # ШАГ 2: VZDUMP (полный бэкап контейнера) # ============================================ if [ "$DO_VZDUMP" = "true" ]; then log "" log "Создание полного бэкапа контейнера (vzdump)..." vzdump "$LXC_ID" \ --compress "$VZDUMP_COMPRESS" \ --storage local \ --mode snapshot \ --notes "Gitea backup $TIMESTAMP" \ 2>&1 | while read line; do log " $line"; done log " ✓ vzdump завершён" fi # ============================================ # ШАГ 3: ОТПРАВКА НА УДАЛЁННЫЙ СЕРВЕР # ============================================ if [ -n "$REMOTE_BACKUP" ] && [ -n "$BACKUP_NAME" ]; then log "" log "Отправка на удалённый сервер: $REMOTE_BACKUP" if scp "$BACKUP_STORAGE/$BACKUP_NAME" "$REMOTE_BACKUP/"; then log " ✓ Отправлено" else warn "Не удалось отправить" fi fi # ============================================ # ШАГ 4: РОТАЦИЯ БЭКАПОВ # ============================================ if [ "$KEEP_BACKUPS" -gt 0 ]; then log "" log "Ротация gitea бэкапов (храним $KEEP_BACKUPS)..." cd "$BACKUP_STORAGE" ls -t gitea-backup-*.tar.gz 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) | xargs -r rm -f log " ✓ Готово" fi # Ротация vzdump (они большие!) if [ "$KEEP_VZDUMP" -gt 0 ] && [ "$DO_VZDUMP" = "true" ]; then log "Ротация vzdump бэкапов (храним $KEEP_VZDUMP)..." cd "$BACKUP_STORAGE" # Удаляем старые .tar.zst, .tar.gz, .tar.lzo и соответствующие .log файлы for ext in tar.zst tar.gz tar.lzo vma.zst vma.gz vma.lzo; do ls -t vzdump-lxc-${LXC_ID}-*.$ext 2>/dev/null | tail -n +$((KEEP_VZDUMP + 1)) | while read f; do rm -f "$f" "${f%.${ext}}.log" log " Удалён: $(basename $f)" done done log " ✓ Готово" fi # ============================================ # ИТОГИ # ============================================ log "" log "==========================================" log " ✅ Бэкап завершён!" log "==========================================" log "" log "Бэкапы Gitea:" ls -lh "$BACKUP_STORAGE"/gitea-backup-*.tar.gz 2>/dev/null | tail -5 || echo " (нет)" log "" if [ "$DO_VZDUMP" = "true" ]; then log "Бэкапы vzdump:" ls -lh "$BACKUP_STORAGE"/vzdump-lxc-${LXC_ID}-*.* 2>/dev/null | tail -3 || echo " (нет)" log "" fi log "Следующий бэкап по расписанию или вручную:" log " $0" log ""