Резервное копирование ботов

В этой статье мы рассмотрим стратегии резервного копирования ботов, включая автоматические бэкапы, восстановление данных и мониторинг целостности резервных копий.

Содержание

Стратегии резервного копирования

Типы резервного копирования

# Полное резервное копирование (Full Backup)
  • Копирование всех данных
  • Большой размер, медленное восстановление
  • Используется для еженедельных/месячных бэкапов
# Инкрементальное резервное копирование (Incremental Backup)
  • Копирование только измененных данных
  • Быстрое выполнение, экономия места
  • Требует полного бэкапа для восстановления
# Дифференциальное резервное копирование (Differential Backup)
  • Копирование данных с последнего полного бэкапа
  • Компромисс между полным и инкрементальным
  • Быстрее полного, но медленнее инкрементального

Планирование стратегии

# backup_strategy.py
from datetime import datetime, timedelta
import os
import shutil
import gzip
import tarfile

class BackupStrategy:
    def __init__(self, backup_dir="/backups"):
        self.backup_dir = backup_dir
        self.retention_policy = {
            'daily': 7,    # 7 дней
            'weekly': 4,   # 4 недели
            'monthly': 12  # 12 месяцев
        }
    
    def create_full_backup(self, source_paths, backup_name):
        """Создание полного бэкапа"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_file = f"{backup_name}_full_{timestamp}.tar.gz"
        backup_path = os.path.join(self.backup_dir, backup_file)
        
        with tarfile.open(backup_path, "w:gz") as tar:
            for source_path in source_paths:
                if os.path.exists(source_path):
                    tar.add(source_path, arcname=os.path.basename(source_path))
        
        return backup_path
    
    def create_incremental_backup(self, source_paths, backup_name, last_backup_time):
        """Создание инкрементального бэкапа"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_file = f"{backup_name}_inc_{timestamp}.tar.gz"
        backup_path = os.path.join(self.backup_dir, backup_file)
        
        with tarfile.open(backup_path, "w:gz") as tar:
            for source_path in source_paths:
                if os.path.exists(source_path):
                    for root, dirs, files in os.walk(source_path):
                        for file in files:
                            file_path = os.path.join(root, file)
                            file_mtime = datetime.fromtimestamp(os.path.getmtime(file_path))
                            
                            if file_mtime > last_backup_time:
                                tar.add(file_path, arcname=os.path.relpath(file_path, source_path))
        
        return backup_path
    
    def cleanup_old_backups(self, backup_name):
        """Очистка старых бэкапов"""
        backup_files = [f for f in os.listdir(self.backup_dir) if f.startswith(backup_name)]
        backup_files.sort()
        
        # Удаление старых бэкапов согласно политике хранения
        for retention_type, count in self.retention_policy.items():
            if retention_type == 'daily':
                # Оставляем последние N ежедневных бэкапов
                daily_backups = [f for f in backup_files if 'full' in f or 'inc' in f]
                if len(daily_backups) > count:
                    for old_backup in daily_backups[:-count]:
                        os.remove(os.path.join(self.backup_dir, old_backup))

# Использование
strategy = BackupStrategy()
backup_path = strategy.create_full_backup(
    ['/home/botuser/telegram-bot', '/home/botuser/discord-bot'],
    'bots_backup'
)
print(f"Backup created: {backup_path}")

Автоматические бэкапы

Скрипт автоматического бэкапа

#!/bin/bash
# auto-backup.sh

# Конфигурация
BACKUP_DIR="/backups"
BOT_DIRS=("/home/botuser/telegram-bot" "/home/botuser/discord-bot" "/home/botuser/vk-bot")
DB_NAME="bot_database"
DB_USER="bot_user"
DB_PASS="bot_password"
RETENTION_DAYS=7

# Создание директории для бэкапов
mkdir -p $BACKUP_DIR

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

# Функция создания бэкапа
create_backup() {
    local backup_name="bot_backup_$(date +%Y%m%d_%H%M%S)"
    local backup_path="$BACKUP_DIR/$backup_name"
    
    log "Начинаем создание бэкапа: $backup_name"
    
    # Создание директории для бэкапа
    mkdir -p $backup_path
    
    # Бэкап файлов ботов
    for bot_dir in "${BOT_DIRS[@]}"; do
        if [ -d "$bot_dir" ]; then
            log "Копирование $bot_dir"
            cp -r "$bot_dir" "$backup_path/"
        else
            log "Предупреждение: $bot_dir не найден"
        fi
    done
    
    # Бэкап базы данных
    log "Создание бэкапа базы данных"
    pg_dump -h localhost -U $DB_USER -d $DB_NAME > "$backup_path/database.sql"
    
    # Создание архива
    log "Создание архива"
    tar -czf "$backup_path.tar.gz" -C $BACKUP_DIR $backup_name
    rm -rf $backup_path
    
    log "Бэкап завершен: $backup_path.tar.gz"
    echo $backup_path.tar.gz
}

# Функция очистки старых бэкапов
cleanup_old_backups() {
    log "Очистка старых бэкапов (старше $RETENTION_DAYS дней)"
    find $BACKUP_DIR -name "bot_backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete
}

# Функция проверки целостности
verify_backup() {
    local backup_file=$1
    log "Проверка целостности: $backup_file"
    
    if tar -tzf "$backup_file" > /dev/null 2>&1; then
        log "Бэкап корректен: $backup_file"
        return 0
    else
        log "Ошибка: Бэкап поврежден: $backup_file"
        return 1
    fi
}

# Основная функция
main() {
    log "=== Начало автоматического бэкапа ==="
    
    # Создание бэкапа
    backup_file=$(create_backup)
    
    if [ $? -eq 0 ]; then
        # Проверка целостности
        if verify_backup "$backup_file"; then
            log "Бэкап успешно создан и проверен"
            
            # Очистка старых бэкапов
            cleanup_old_backups
            
            # Отправка уведомления об успехе
            curl -X POST -H 'Content-type: application/json' \
                --data '{"text":"Backup completed successfully: '$backup_file'"}' \
                https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
        else
            log "Ошибка: Бэкап поврежден"
            exit 1
        fi
    else
        log "Ошибка создания бэкапа"
        exit 1
    fi
    
    log "=== Завершение автоматического бэкапа ==="
}

# Запуск
main "$@"

Cron настройка

# Добавление в crontab
# Ежедневный бэкап в 2:00
0 2   * /usr/local/bin/auto-backup.sh

# Еженедельный полный бэкап в воскресенье в 1:00
0 1   0 /usr/local/bin/auto-backup.sh --full

# Ежемесячный бэкап 1 числа в 0:00
0 0 1   /usr/local/bin/auto-backup.sh --monthly

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

PostgreSQL бэкап

# database_backup.py
import subprocess
import os
import gzip
from datetime import datetime
import logging

class DatabaseBackup:
    def __init__(self, db_config):
        self.db_config = db_config
        self.logger = logging.getLogger(__name__)
    
    def create_postgresql_backup(self, backup_path):
        """Создание бэкапа PostgreSQL"""
        try:
            # Команда pg_dump
            cmd = [
                'pg_dump',
                '-h', self.db_config['host'],
                '-U', self.db_config['user'],
                '-d', self.db_config['database'],
                '-f', backup_path,
                '--verbose',
                '--no-password'
            ]
            
            # Установка переменной окружения для пароля
            env = os.environ.copy()
            env['PGPASSWORD'] = self.db_config['password']
            
            # Выполнение команды
            result = subprocess.run(cmd, env=env, capture_output=True, text=True)
            
            if result.returncode == 0:
                self.logger.info(f"PostgreSQL backup created: {backup_path}")
                return True
            else:
                self.logger.error(f"PostgreSQL backup failed: {result.stderr}")
                return False
                
        except Exception as e:
            self.logger.error(f"Error creating PostgreSQL backup: {e}")
            return False
    
    def create_mysql_backup(self, backup_path):
        """Создание бэкапа MySQL"""
        try:
            # Команда mysqldump
            cmd = [
                'mysqldump',
                '-h', self.db_config['host'],
                '-u', self.db_config['user'],
                f'-p{self.db_config["password"]}',
                self.db_config['database'],
                '--single-transaction',
                '--routines',
                '--triggers'
            ]
            
            # Выполнение команды
            with open(backup_path, 'w') as f:
                result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, text=True)
            
            if result.returncode == 0:
                self.logger.info(f"MySQL backup created: {backup_path}")
                return True
            else:
                self.logger.error(f"MySQL backup failed: {result.stderr}")
                return False
                
        except Exception as e:
            self.logger.error(f"Error creating MySQL backup: {e}")
            return False
    
    def create_sqlite_backup(self, db_path, backup_path):
        """Создание бэкапа SQLite"""
        try:
            import sqlite3
            
            # Подключение к базе данных
            source = sqlite3.connect(db_path)
            backup = sqlite3.connect(backup_path)
            
            # Создание бэкапа
            source.backup(backup)
            
            # Закрытие соединений
            backup.close()
            source.close()
            
            self.logger.info(f"SQLite backup created: {backup_path}")
            return True
            
        except Exception as e:
            self.logger.error(f"Error creating SQLite backup: {e}")
            return False
    
    def compress_backup(self, backup_path):
        """Сжатие бэкапа"""
        try:
            compressed_path = f"{backup_path}.gz"
            
            with open(backup_path, 'rb') as f_in:
                with gzip.open(compressed_path, 'wb') as f_out:
                    f_out.writelines(f_in)
            
            # Удаление несжатого файла
            os.remove(backup_path)
            
            self.logger.info(f"Backup compressed: {compressed_path}")
            return compressed_path
            
        except Exception as e:
            self.logger.error(f"Error compressing backup: {e}")
            return backup_path

# Использование
db_backup = DatabaseBackup({
    'host': 'localhost',
    'user': 'bot_user',
    'password': 'bot_password',
    'database': 'bot_database'
})

backup_path = f"/backups/db_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.sql"
if db_backup.create_postgresql_backup(backup_path):
    compressed_path = db_backup.compress_backup(backup_path)
    print(f"Database backup created: {compressed_path}")

Облачное хранение

Интеграция с AWS S3

# cloud_backup.py
import boto3
import os
from datetime import datetime
import logging

class CloudBackup:
    def __init__(self, aws_config):
        self.aws_config = aws_config
        self.s3_client = boto3.client(
            's3',
            aws_access_key_id=aws_config['access_key'],
            aws_secret_access_key=aws_config['secret_key'],
            region_name=aws_config['region']
        )
        self.logger = logging.getLogger(__name__)
    
    def upload_to_s3(self, local_file_path, s3_key):
        """Загрузка файла в S3"""
        try:
            self.s3_client.upload_file(
                local_file_path,
                self.aws_config['bucket'],
                s3_key
            )
            self.logger.info(f"File uploaded to S3: {s3_key}")
            return True
        except Exception as e:
            self.logger.error(f"Error uploading to S3: {e}")
            return False
    
    def download_from_s3(self, s3_key, local_file_path):
        """Скачивание файла из S3"""
        try:
            self.s3_client.download_file(
                self.aws_config['bucket'],
                s3_key,
                local_file_path
            )
            self.logger.info(f"File downloaded from S3: {s3_key}")
            return True
        except Exception as e:
            self.logger.error(f"Error downloading from S3: {e}")
            return False
    
    def list_backups(self, prefix="bot_backup_"):
        """Список бэкапов в S3"""
        try:
            response = self.s3_client.list_objects_v2(
                Bucket=self.aws_config['bucket'],
                Prefix=prefix
            )
            
            backups = []
            if 'Contents' in response:
                for obj in response['Contents']:
                    backups.append({
                        'key': obj['Key'],
                        'size': obj['Size'],
                        'last_modified': obj['LastModified']
                    })
            
            return backups
        except Exception as e:
            self.logger.error(f"Error listing backups: {e}")
            return []
    
    def delete_old_backups(self, retention_days=30):
        """Удаление старых бэкапов"""
        try:
            backups = self.list_backups()
            cutoff_date = datetime.now() - timedelta(days=retention_days)
            
            for backup in backups:
                if backup['last_modified'].replace(tzinfo=None) < cutoff_date:
                    self.s3_client.delete_object(
                        Bucket=self.aws_config['bucket'],
                        Key=backup['key']
                    )
                    self.logger.info(f"Deleted old backup: {backup['key']}")
            
            return True
        except Exception as e:
            self.logger.error(f"Error deleting old backups: {e}")
            return False

# Использование
cloud_backup = CloudBackup({
    'access_key': 'YOUR_ACCESS_KEY',
    'secret_key': 'YOUR_SECRET_KEY',
    'region': 'us-east-1',
    'bucket': 'your-backup-bucket'
})

# Загрузка бэкапа в S3
s3_key = f"bot_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.tar.gz"
if cloud_backup.upload_to_s3("/backups/bot_backup.tar.gz", s3_key):
    print("Backup uploaded to S3 successfully")

Интеграция с Google Cloud Storage

# gcs_backup.py
from google.cloud import storage
import os
from datetime import datetime
import logging

class GCSBackup:
    def __init__(self, gcs_config):
        self.gcs_config = gcs_config
        self.client = storage.Client()
        self.bucket = self.client.bucket(gcs_config['bucket'])
        self.logger = logging.getLogger(__name__)
    
    def upload_to_gcs(self, local_file_path, gcs_key):
        """Загрузка файла в Google Cloud Storage"""
        try:
            blob = self.bucket.blob(gcs_key)
            blob.upload_from_filename(local_file_path)
            self.logger.info(f"File uploaded to GCS: {gcs_key}")
            return True
        except Exception as e:
            self.logger.error(f"Error uploading to GCS: {e}")
            return False
    
    def download_from_gcs(self, gcs_key, local_file_path):
        """Скачивание файла из Google Cloud Storage"""
        try:
            blob = self.bucket.blob(gcs_key)
            blob.download_to_filename(local_file_path)
            self.logger.info(f"File downloaded from GCS: {gcs_key}")
            return True
        except Exception as e:
            self.logger.error(f"Error downloading from GCS: {e}")
            return False
    
    def set_lifecycle_policy(self, retention_days=30):
        """Установка политики жизненного цикла"""
        try:
            lifecycle_rule = {
                "lifecycle": {
                    "rule": [
                        {
                            "action": {"type": "Delete"},
                            "condition": {"age": retention_days}
                        }
                    ]
                }
            }
            
            self.bucket.lifecycle_rules = lifecycle_rule
            self.bucket.patch()
            
            self.logger.info(f"Lifecycle policy set: {retention_days} days")
            return True
        except Exception as e:
            self.logger.error(f"Error setting lifecycle policy: {e}")
            return False

# Использование
gcs_backup = GCSBackup({
    'bucket': 'your-backup-bucket'
})

# Загрузка бэкапа в GCS
gcs_key = f"bot_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.tar.gz"
if gcs_backup.upload_to_gcs("/backups/bot_backup.tar.gz", gcs_key):
    print("Backup uploaded to GCS successfully")

Восстановление данных

Скрипт восстановления

#!/bin/bash
# restore-backup.sh

# Конфигурация
BACKUP_DIR="/backups"
RESTORE_DIR="/tmp/restore"
DB_NAME="bot_database"
DB_USER="bot_user"
DB_PASS="bot_password"

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

# Функция восстановления из архива
restore_from_archive() {
    local backup_file=$1
    local restore_path=$2
    
    log "Восстановление из архива: $backup_file"
    
    # Создание директории для восстановления
    mkdir -p $restore_path
    
    # Извлечение архива
    tar -xzf "$backup_file" -C $restore_path
    
    if [ $? -eq 0 ]; then
        log "Архив успешно извлечен"
        return 0
    else
        log "Ошибка извлечения архива"
        return 1
    fi
}

# Функция восстановления файлов
restore_files() {
    local source_path=$1
    local target_path=$2
    
    log "Восстановление файлов из $source_path в $target_path"
    
    # Остановка ботов
    systemctl stop telegram-bot
    systemctl stop discord-bot
    systemctl stop vk-bot
    
    # Создание бэкапа текущих файлов
    log "Создание бэкапа текущих файлов"
    cp -r $target_path "${target_path}_backup_$(date +%Y%m%d_%H%M%S)"
    
    # Восстановление файлов
    cp -r $source_path/* $target_path/
    
    # Установка правильных прав
    chown -R botuser:botuser $target_path
    chmod -R 755 $target_path
    
    log "Файлы восстановлены"
}

# Функция восстановления базы данных
restore_database() {
    local db_backup_file=$1
    
    log "Восстановление базы данных из $db_backup_file"
    
    # Остановка сервисов
    systemctl stop telegram-bot
    systemctl stop discord-bot
    systemctl stop vk-bot
    
    # Создание бэкапа текущей базы данных
    log "Создание бэкапа текущей базы данных"
    pg_dump -h localhost -U $DB_USER -d $DB_NAME > "${DB_NAME}_backup_$(date +%Y%m%d_%H%M%S).sql"
    
    # Восстановление базы данных
    if [ -f "$db_backup_file" ]; then
        if [[ "$db_backup_file" == *.gz ]]; then
            gunzip -c "$db_backup_file" | psql -h localhost -U $DB_USER -d $DB_NAME
        else
            psql -h localhost -U $DB_USER -d $DB_NAME < "$db_backup_file"
        fi
        
        if [ $? -eq 0 ]; then
            log "База данных восстановлена"
        else
            log "Ошибка восстановления базы данных"
            return 1
        fi
    else
        log "Файл бэкапа базы данных не найден: $db_backup_file"
        return 1
    fi
}

# Функция полного восстановления
full_restore() {
    local backup_file=$1
    
    log "=== Начало полного восстановления ==="
    
    # Проверка существования файла бэкапа
    if [ ! -f "$backup_file" ]; then
        log "Ошибка: Файл бэкапа не найден: $backup_file"
        exit 1
    fi
    
    # Восстановление из архива
    if restore_from_archive "$backup_file" "$RESTORE_DIR"; then
        # Поиск файлов бэкапа
        backup_name=$(basename "$backup_file" .tar.gz)
        extracted_path="$RESTORE_DIR/$backup_name"
        
        # Восстановление файлов ботов
        for bot_dir in telegram-bot discord-bot vk-bot; do
            if [ -d "$extracted_path/$bot_dir" ]; then
                restore_files "$extracted_path/$bot_dir" "/home/botuser/$bot_dir"
            fi
        done
        
        # Восстановление базы данных
        if [ -f "$extracted_path/database.sql" ]; then
            restore_database "$extracted_path/database.sql"
        fi
        
        # Запуск сервисов
        log "Запуск сервисов"
        systemctl start telegram-bot
        systemctl start discord-bot
        systemctl start vk-bot
        
        # Очистка временных файлов
        rm -rf $RESTORE_DIR
        
        log "=== Восстановление завершено ==="
    else
        log "Ошибка восстановления из архива"
        exit 1
    fi
}

# Основная функция
main() {
    if [ $# -eq 0 ]; then
        echo "Использование: $0 <backup_file>"
        echo "Пример: $0 /backups/bot_backup_20231201_120000.tar.gz"
        exit 1
    fi
    
    backup_file=$1
    full_restore "$backup_file"
}

# Запуск
main "$@"

Мониторинг и тестирование

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

# backup_monitor.py
import os
import time
import smtplib
from email.mime.text import MIMEText
from datetime import datetime, timedelta
import logging

class BackupMonitor:
    def __init__(self, backup_dir, email_config):
        self.backup_dir = backup_dir
        self.email_config = email_config
        self.logger = logging.getLogger(__name__)
    
    def check_backup_freshness(self, max_age_hours=24):
        """Проверка свежести бэкапов"""
        try:
            backup_files = [f for f in os.listdir(self.backup_dir) if f.endswith('.tar.gz')]
            
            if not backup_files:
                self.send_alert("No backup files found")
                return False
            
            # Поиск самого свежего бэкапа
            latest_backup = max(backup_files, key=lambda f: os.path.getmtime(os.path.join(self.backup_dir, f)))
            latest_backup_path = os.path.join(self.backup_dir, latest_backup)
            
            # Проверка возраста
            backup_age = datetime.now() - datetime.fromtimestamp(os.path.getmtime(latest_backup_path))
            
            if backup_age.total_seconds() > max_age_hours * 3600:
                self.send_alert(f"Backup is too old: {latest_backup} (age: {backup_age})")
                return False
            
            self.logger.info(f"Latest backup is fresh: {latest_backup}")
            return True
            
        except Exception as e:
            self.logger.error(f"Error checking backup freshness: {e}")
            return False
    
    def check_backup_integrity(self):
        """Проверка целостности бэкапов"""
        try:
            backup_files = [f for f in os.listdir(self.backup_dir) if f.endswith('.tar.gz')]
            
            for backup_file in backup_files:
                backup_path = os.path.join(self.backup_dir, backup_file)
                
                # Проверка архива
                if not self.verify_tar_archive(backup_path):
                    self.send_alert(f"Backup integrity check failed: {backup_file}")
                    return False
            
            self.logger.info("All backups passed integrity check")
            return True
            
        except Exception as e:
            self.logger.error(f"Error checking backup integrity: {e}")
            return False
    
    def verify_tar_archive(self, archive_path):
        """Проверка целостности tar архива"""
        try:
            import tarfile
            with tarfile.open(archive_path, 'r:gz') as tar:
                tar.getmembers()
            return True
        except Exception as e:
            self.logger.error(f"Archive verification failed for {archive_path}: {e}")
            return False
    
    def send_alert(self, message):
        """Отправка уведомления"""
        try:
            msg = MIMEText(f"Backup Alert: {message}")
            msg['Subject'] = 'Backup Alert'
            msg['From'] = self.email_config['from']
            msg['To'] = self.email_config['to']
            
            with smtplib.SMTP(self.email_config['smtp_server'], self.email_config['smtp_port']) as server:
                server.starttls()
                server.login(self.email_config['username'], self.email_config['password'])
                server.send_message(msg)
            
            self.logger.info(f"Alert sent: {message}")
        except Exception as e:
            self.logger.error(f"Error sending alert: {e}")
    
    def run_monitoring(self):
        """Запуск мониторинга"""
        while True:
            try:
                # Проверка свежести
                if not self.check_backup_freshness():
                    continue
                
                # Проверка целостности
                if not self.check_backup_integrity():
                    continue
                
                self.logger.info("Backup monitoring check passed")
                time.sleep(3600)  # Проверка каждый час
                
            except KeyboardInterrupt:
                break
            except Exception as e:
                self.logger.error(f"Error in monitoring loop: {e}")
                time.sleep(3600)

# Использование
monitor = BackupMonitor(
    backup_dir="/backups",
    email_config={
        'smtp_server': 'smtp.gmail.com',
        'smtp_port': 587,
        'username': 'your_email@gmail.com',
        'password': 'your_password',
        'from': 'your_email@gmail.com',
        'to': 'admin@yourdomain.com'
    }
)

monitor.run_monitoring()

Тестирование восстановления

#!/bin/bash
# test-restore.sh

# Конфигурация
TEST_DIR="/tmp/backup_test"
BACKUP_FILE="/backups/bot_backup_20231201_120000.tar.gz"

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

# Функция тестирования восстановления
test_restore() {
    local backup_file=$1
    
    log "=== Начало тестирования восстановления ==="
    
    # Создание тестовой директории
    mkdir -p $TEST_DIR
    cd $TEST_DIR
    
    # Извлечение архива
    log "Извлечение архива: $backup_file"
    tar -xzf "$backup_file"
    
    if [ $? -eq 0 ]; then
        log "Архив успешно извлечен"
        
        # Проверка содержимого
        log "Проверка содержимого архива"
        find . -type f -name "*.py" | head -5
        find . -type f -name "*.sql" | head -5
        
        # Проверка базы данных
        if [ -f "*/database.sql" ]; then
            log "Файл базы данных найден"
            
            # Проверка синтаксиса SQL
            if head -10 */database.sql | grep -q "CREATE TABLE\|INSERT INTO"; then
                log "SQL файл выглядит корректно"
            else
                log "Предупреждение: SQL файл может быть поврежден"
            fi
        else
            log "Предупреждение: Файл базы данных не найден"
        fi
        
        log "Тестирование восстановления завершено успешно"
    else
        log "Ошибка извлечения архива"
        return 1
    fi
    
    # Очистка
    cd /
    rm -rf $TEST_DIR
    
    log "=== Тестирование восстановления завершено ==="
    return 0
}

# Основная функция
main() {
    if [ $# -eq 0 ]; then
        echo "Использование: $0 <backup_file>"
        echo "Пример: $0 /backups/bot_backup_20231201_120000.tar.gz"
        exit 1
    fi
    
    backup_file=$1
    
    if [ ! -f "$backup_file" ]; then
        log "Ошибка: Файл бэкапа не найден: $backup_file"
        exit 1
    fi
    
    test_restore "$backup_file"
}

# Запуск
main "$@"

Аварийное восстановление

План аварийного восстановления

#!/bin/bash
# disaster-recovery.sh

# Конфигурация
BACKUP_SERVER="backup.yourdomain.com"
BACKUP_USER="backup_user"
BACKUP_DIR="/backups"
LOCAL_RESTORE_DIR="/tmp/disaster_recovery"

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

# Функция скачивания бэкапа
download_backup() {
    local backup_file=$1
    local local_path=$2
    
    log "Скачивание бэкапа: $backup_file"
    
    # Скачивание через SCP
    scp "$BACKUP_USER@$BACKUP_SERVER:$BACKUP_DIR/$backup_file" "$local_path"
    
    if [ $? -eq 0 ]; then
        log "Бэкап успешно скачан"
        return 0
    else
        log "Ошибка скачивания бэкапа"
        return 1
    fi
}

# Функция быстрого восстановления
quick_recovery() {
    local backup_file=$1
    
    log "=== Начало быстрого восстановления ==="
    
    # Скачивание бэкапа
    local_backup_path="$LOCAL_RESTORE_DIR/$(basename $backup_file)"
    if ! download_backup "$backup_file" "$local_backup_path"; then
        return 1
    fi
    
    # Восстановление критически важных сервисов
    log "Восстановление критически важных сервисов"
    
    # Остановка всех сервисов
    systemctl stop telegram-bot
    systemctl stop discord-bot
    systemctl stop vk-bot
    systemctl stop nginx
    
    # Извлечение архива
    cd $LOCAL_RESTORE_DIR
    tar -xzf "$(basename $backup_file)"
    
    # Восстановление конфигурации Nginx
    if [ -f "*/nginx.conf" ]; then
        cp "*/nginx.conf" /etc/nginx/nginx.conf
        systemctl start nginx
        log "Nginx восстановлен"
    fi
    
    # Восстановление базы данных
    if [ -f "*/database.sql" ]; then
        # Создание новой базы данных
        createdb -U postgres bot_database_recovery
        
        # Восстановление данных
        psql -U postgres -d bot_database_recovery < "*/database.sql"
        
        # Переключение на восстановленную базу данных
        systemctl stop postgresql
        # Здесь должна быть логика переключения на восстановленную базу данных
        systemctl start postgresql
        
        log "База данных восстановлена"
    fi
    
    # Восстановление файлов ботов
    for bot_dir in telegram-bot discord-bot vk-bot; do
        if [ -d "*/$bot_dir" ]; then
            cp -r "*/$bot_dir" "/home/botuser/"
            chown -R botuser:botuser "/home/botuser/$bot_dir"
            systemctl start "$bot_dir"
            log "$bot_dir восстановлен"
        fi
    done
    
    # Очистка
    rm -rf $LOCAL_RESTORE_DIR
    
    log "=== Быстрое восстановление завершено ==="
    return 0
}

# Функция полного восстановления
full_recovery() {
    local backup_file=$1
    
    log "=== Начало полного восстановления ==="
    
    # Скачивание бэкапа
    local_backup_path="$LOCAL_RESTORE_DIR/$(basename $backup_file)"
    if ! download_backup "$backup_file" "$local_backup_path"; then
        return 1
    fi
    
    # Полное восстановление системы
    # Здесь должна быть логика полного восстановления системы
    
    log "=== Полное восстановление завершено ==="
    return 0
}

# Основная функция
main() {
    if [ $# -lt 2 ]; then
        echo "Использование: $0 <recovery_type> <backup_file>"
        echo "Типы восстановления: quick, full"
        echo "Пример: $0 quick bot_backup_20231201_120000.tar.gz"
        exit 1
    fi
    
    recovery_type=$1
    backup_file=$2
    
    # Создание директории для восстановления
    mkdir -p $LOCAL_RESTORE_DIR
    
    case $recovery_type in
        "quick")
            quick_recovery "$backup_file"
            ;;
        "full")
            full_recovery "$backup_file"
            ;;
        *)
            echo "Неизвестный тип восстановления: $recovery_type"
            exit 1
            ;;
    esac
}

# Запуск
main "$@"

Заключение

В этой статье мы рассмотрели стратегии резервного копирования ботов:
  • ✅ Стратегии резервного копирования и планирование
  • ✅ Автоматические бэкапы и cron настройка
  • ✅ Резервное копирование различных типов баз данных
  • ✅ Интеграция с облачными хранилищами
  • ✅ Восстановление данных и тестирование
  • ✅ Мониторинг и проверка целостности
  • ✅ План аварийного восстановления
Правильная стратегия резервного копирования обеспечивает надежность и непрерывность работы ботов.

Полезные ссылки

628 просмотров
45 лайков
0 комментариев