🤖 Автоматическое резервное копирование

Настройка автоматизированных систем резервного копирования

Преимущества автоматизации

  • Исключение человеческого фактора
  • Соблюдение расписания
  • Стандартизация процедур
  • Снижение времени на обслуживание

Архитектура системы бэкапов

Компоненты системы

$$┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ Источники │ ──▶│ Сценарии │ ──▶│ Хранилища │ │ данных │ │ резервного │ │ бэкапов │ │ │ │ копирования │ │ │ ├─────────────────┤ ├──────────────────┤ ├─────────────────┤ │ • База данных │ │ • Полные бэкапы │ │ • Локальные │ │ • Файлы контента│ │ • Инкрементальные│ │ • Сетевые │ │ • Конфигурации │ │ • Сжатие/шифровка│ │ • Облачные │ │ • Логи │ │ • Верификация │ │ • Архивные │ └─────────────────┘ └──────────────────┘ └─────────────────┘$$

🗄️ Скрипт для бэкапа базы данных

#!/bin/bash
# postgresql_backup.sh

# Конфигурация
DB_NAME="wiki_db"
DB_USER="postgres"
BACKUP_DIR="/backup/postgresql"
RETENTION_DAYS=30
LOG_FILE="/var/log/backup/postgresql.log"

# Создание директорий
mkdir -p "$BACKUP_DIR"
mkdir -p "$(dirname "$LOG_FILE")"

# Функция логирования
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Начало бэкапа
log "Начало резервного копирования базы данных $DB_NAME"

# Имя файла с временной меткой
BACKUP_FILE="$BACKUP_DIR/wiki_db_$(date +%Y%m%d_%H%M%S).sql"

# Создание бэкапа
if sudo -u postgres pg_dump "$DB_NAME" > "$BACKUP_FILE"; then
    log "Бэкап базы данных создан: $BACKUP_FILE"
    
    # Сжатие
    if gzip "$BACKUP_FILE"; then
        log "Бэкап сжат: ${BACKUP_FILE}.gz"
        BACKUP_FILE="${BACKUP_FILE}.gz"
    else
        log "ОШИБКА: Не удалось сжать бэкап"
    fi
    
    # Проверка размера
    SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
    log "Размер бэкапа: $SIZE"
    
    # Верификация (попытка восстановить в тестовую БД)
    if command -v psql >/dev/null; then
        TEST_DB="test_restore_$(date +%s)"
        if sudo -u postgres createdb "$TEST_DB" && \
           sudo -u postgres zcat "$BACKUP_FILE" | sudo -u postgres psql "$TEST_DB" >/dev/null 2>&1; then
            log "Верификация бэкапа: УСПЕШНО"
            sudo -u postgres dropdb "$TEST_DB"
        else
            log "ОШИБКА: Верификация бэкапа не удалась"
            sudo -u postgres dropdb "$TEST_DB" 2>/dev/null
        fi
    fi
    
else
    log "ОШИБКА: Не удалось создать бэкап базы данных"
    exit 1
fi

# Очистка старых бэкапов
log "Очистка бэкапов старше $RETENTION_DAYS дней"
find "$BACKUP_DIR" -name "wiki_db_*.sql.gz" -mtime +$RETENTION_DAYS -delete
DELETED=$(find "$BACKUP_DIR" -name "wiki_db_*.sql.gz" -mtime +$RETENTION_DAYS 2>/dev/null | wc -l)
log "Удалено старых бэкапов: $DELETED"

# Проверка доступного места
AVAILABLE=$(df "$BACKUP_DIR" | awk 'NR==2 {print $4}')
if [ "$AVAILABLE" -lt 1048576 ]; then  # Менее 1GB
    log "ПРЕДУПРЕЖДЕНИЕ: Мало места для бэкапов: $(df -h "$BACKUP_DIR" | awk 'NR==2 {print $4}')"
fi

log "Резервное копирование базы данных завершено"

Скрипт для бэкапа файлов

#!/bin/bash
# files_backup.sh

# Конфигурация
SOURCE_DIRS=(
    "/opt/wiki-iridium"
    "/etc/nginx"
    "/etc/ssl"
    "/home"
)
BACKUP_DIR="/backup/files"
RETENTION_DAYS=14
LOG_FILE="/var/log/backup/files.log"

# Создание директорий
mkdir -p "$BACKUP_DIR"
mkdir -p "$(dirname "$LOG_FILE")"

# Функция логирования
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

log "Начало резервного копирования файлов"

# Создание архива
BACKUP_FILE="$BACKUP_DIR/files_$(date +%Y%m%d_%H%M%S).tar.gz"

# Исключения
EXCLUDE_FILE="/tmp/backup_exclude_$$"
cat > "$EXCLUDE_FILE" << EOF
*.log
*.tmp
*.cache
__pycache__
node_modules
.git
EOF

# Создание архива
if tar -czf "$BACKUP_FILE" \
    --exclude-from="$EXCLUDE_FILE" \
    "${SOURCE_DIRS[@]}" 2>>"$LOG_FILE"; then
    
    log "Архив создан: $BACKUP_FILE"
    
    # Размер архива
    SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
    log "Размер архива: $SIZE"
    
    # Верификация архива
    if tar -tzf "$BACKUP_FILE" >/dev/null 2>&1; then
        log "Верификация архива: УСПЕШНО"
    else
        log "ОШИБКА: Архив поврежден"
    fi
    
else
    log "ОШИБКА: Не удалось создать архив"
    rm -f "$EXCLUDE_FILE"
    exit 1
fi

# Очистка
rm -f "$EXCLUDE_FILE"

# Очистка старых бэкапов
log "Очистка архивов старше $RETENTION_DAYS дней"
find "$BACKUP_DIR" -name "files_*.tar.gz" -mtime +$RETENTION_DAYS -delete

log "Резервное копирование файлов завершено"

Мастер-скрипт для полного бэкапа

#!/bin/bash
# full_backup.sh

SCRIPT_DIR="/opt/backup-scripts"
LOG_FILE="/var/log/backup/full_backup.log"

# Функция логирования
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Функция отправки уведомлений
send_notification() {
    local status="$1"
    local message="$2"
    
    # Email уведомление
    echo "$message" | mail -s "Бэкап $(hostname): $status" admin@company.com
    
    # Slack/Discord webhook (опционально)
    # curl -X POST -H 'Content-type: application/json' \
    #   --data '{"text":"'"$message"'"}' \
    #   YOUR_WEBHOOK_URL
}

log "=== НАЧАЛО ПОЛНОГО РЕЗЕРВНОГО КОПИРОВАНИЯ ==="

# Массив скриптов для выполнения
BACKUP_SCRIPTS=(
    "$SCRIPT_DIR/postgresql_backup.sh"
    "$SCRIPT_DIR/files_backup.sh"
)

SUCCESS_COUNT=0
TOTAL_COUNT=${#BACKUP_SCRIPTS[@]}

# Выполнение скриптов
for script in "${BACKUP_SCRIPTS[@]}"; do
    if [ -x "$script" ]; then
        log "Выполнение: $script"
        if "$script"; then
            log "УСПЕШНО: $script"
            ((SUCCESS_COUNT++))
        else
            log "ОШИБКА: $script"
        fi
    else
        log "ПРОПУЩЕН: $script (не найден или не исполняемый)"
    fi
done

# Дополнительные проверки
log "Проверка свободного места"
BACKUP_USAGE=$(du -sh /backup 2>/dev/null | cut -f1)
DISK_USAGE=$(df -h /backup 2>/dev/null | awk 'NR==2 {print $5}')
log "Использование: /backup = $BACKUP_USAGE, диск = $DISK_USAGE"

# Итоговый отчет
if [ "$SUCCESS_COUNT" -eq "$TOTAL_COUNT" ]; then
    STATUS="УСПЕШНО"
    MESSAGE="Все бэкапы ($SUCCESS_COUNT/$TOTAL_COUNT) выполнены успешно"
else
    STATUS="ЧАСТИЧНО"
    MESSAGE="Выполнено $SUCCESS_COUNT из $TOTAL_COUNT бэкапов"
fi

log "$MESSAGE"
log "=== ЗАВЕРШЕНИЕ ПОЛНОГО РЕЗЕРВНОГО КОПИРОВАНИЯ ==="

# Отправка уведомления
send_notification "$STATUS" "$MESSAGE"

# Код возврата
[ "$SUCCESS_COUNT" -eq "$TOTAL_COUNT" ]

📅 Настройка Cron

# Редактирование crontab
sudo crontab -e

# Ежедневный бэкап в 2:00
0 2 * * * /opt/backup-scripts/full_backup.sh

# Проверка состояния бэкапов каждые 6 часов
0 */6 * * * /opt/backup-scripts/check_backups.sh

# Еженедельная очистка в воскресенье в 3:00
0 3 * * 0 /opt/backup-scripts/cleanup_old_backups.sh

# Ежемесячное тестирование восстановления (первое воскресенье месяца)
0 4 1-7 * 0 /opt/backup-scripts/test_restore.sh

Скрипт мониторинга бэкапов

#!/bin/bash
# check_backups.sh

BACKUP_DIR="/backup"
LOG_FILE="/var/log/backup/monitoring.log"
ALERT_EMAIL="admin@company.com"

# Функция логирования
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Функция алерта
alert() {
    local message="$1"
    log "АЛЕРТ: $message"
    echo "$message" | mail -s " Алерт бэкапа $(hostname)" "$ALERT_EMAIL"
}

log "Начало проверки состояния бэкапов"

# Проверка последнего бэкапа БД
LAST_DB_BACKUP=$(find "$BACKUP_DIR/postgresql" -name "*.sql.gz" -mtime -1 | head -1)
if [ -z "$LAST_DB_BACKUP" ]; then
    alert "Нет свежего бэкапа базы данных (последние 24 часа)"
else
    log "Найден свежий бэкап БД: $(basename "$LAST_DB_BACKUP")"
fi

# Проверка последнего бэкапа файлов
LAST_FILES_BACKUP=$(find "$BACKUP_DIR/files" -name "*.tar.gz" -mtime -1 | head -1)
if [ -z "$LAST_FILES_BACKUP" ]; then
    alert "Нет свежего бэкапа файлов (последние 24 часа)"
else
    log "Найден свежий бэкап файлов: $(basename "$LAST_FILES_BACKUP")"
fi

# Проверка доступного места (менее 10% = алерт)
DISK_USAGE=$(df "$BACKUP_DIR" | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt 90 ]; then
    alert "Критически мало места для бэкапов: ${DISK_USAGE}%"
elif [ "$DISK_USAGE" -gt 80 ]; then
    log "ПРЕДУПРЕЖДЕНИЕ: Мало места для бэкапов: ${DISK_USAGE}%"
fi

# Проверка целостности последних бэкапов
if [ -n "$LAST_DB_BACKUP" ]; then
    if ! gzip -t "$LAST_DB_BACKUP" 2>/dev/null; then
        alert "Поврежден последний бэкап БД: $(basename "$LAST_DB_BACKUP")"
    fi
fi

if [ -n "$LAST_FILES_BACKUP" ]; then
    if ! tar -tzf "$LAST_FILES_BACKUP" >/dev/null 2>&1; then
        alert "Поврежден последний бэкап файлов: $(basename "$LAST_FILES_BACKUP")"
    fi
fi

log "Проверка состояния бэкапов завершена"

Безопасность автоматических бэкапов

Ограничение прав доступа

#!/bin/bash
# setup_backup_security.sh

# Создание пользователя для бэкапов
sudo useradd -r -s /bin/bash -d /var/lib/backup backup-user

# Настройка директорий
sudo mkdir -p /backup/{postgresql,files}
sudo mkdir -p /var/log/backup
sudo mkdir -p /opt/backup-scripts

# Права доступа
sudo chown -R backup-user:backup-user /backup
sudo chown -R backup-user:backup-user /var/log/backup
sudo chown -R backup-user:backup-user /opt/backup-scripts

sudo chmod 750 /backup
sudo chmod 750 /var/log/backup
sudo chmod 755 /opt/backup-scripts

# Добавление в группу postgres для доступа к БД
sudo usermod -a -G postgres backup-user

# Настройка sudo для backup-user
echo "backup-user ALL=(postgres) NOPASSWD: /usr/bin/pg_dump, /usr/bin/createdb, /usr/bin/dropdb, /usr/bin/psql" | sudo tee /etc/sudoers.d/backup-user

Шифрование бэкапов

#!/bin/bash
# encrypted_backup.sh

# Конфигурация
GPG_RECIPIENT="admin@company.com"
BACKUP_DIR="/backup/encrypted"

# Функция шифрования
encrypt_backup() {
    local source_file="$1"
    local encrypted_file="${source_file}.gpg"
    
    if gpg --trust-model always --encrypt \
           --recipient "$GPG_RECIPIENT" \
           --output "$encrypted_file" \
           "$source_file"; then
        echo "Зашифрован: $encrypted_file"
        rm "$source_file"  # Удаляем незашифрованную версию
        return 0
    else
        echo "ОШИБКА: Не удалось зашифровать $source_file"
        return 1
    fi
}

# Пример использования
BACKUP_FILE="/backup/postgresql/wiki_db_$(date +%Y%m%d_%H%M%S).sql.gz"
# ... создание бэкапа ...
encrypt_backup "$BACKUP_FILE"

Оптимизация производительности

Сжатие и параллелизм

#!/bin/bash
# optimized_backup.sh

# Использование pigz для параллельного сжатия
if command -v pigz >/dev/null; then
    GZIP_CMD="pigz"
else
    GZIP_CMD="gzip"
fi

# Параллельное создание разных типов бэкапов
(
    echo "Запуск бэкапа БД..."
    /opt/backup-scripts/postgresql_backup.sh
) &

(
    echo "Запуск бэкапа файлов..."
    /opt/backup-scripts/files_backup.sh
) &

# Ожидание завершения всех процессов
wait

echo "Все бэкапы завершены"

Лучшие практики

  1. Мониторинг - всегда проверяйте успешность бэкапов
  2. Тестирование - регулярно проверяйте восстановление
  3. Логирование - ведите подробные логи всех операций
  4. Уведомления - настройте алерты при сбоях
  5. Безопасность - ограничьте доступ и используйте шифрование
  6. Производительность - оптимизируйте время выполнения
  7. Мониторинг ресурсов - следите за использованием диска и сети