commit fdab844d794972f237773552e381cf5808ba95b5 Author: Sergey Paramoshkin Date: Fri Sep 19 11:26:38 2025 +0300 first commit diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..011941f --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +# MySQL root passwords for each environment +MYSQL_ROOT_PASSWORD_PROD=your_prod_password_here +MYSQL_ROOT_PASSWORD_TQO=your_tqo_password_here +MYSQL_ROOT_PASSWORD_EKS=your_eks_password_here + +# Optional: Override default S3 settings +# S3_BUCKET=selectel:backup_db +# S3_PATH=dot +# KEEP_BACKUPS=7 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ed60ac4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM mariadb:10.3.25 + +# Install rclone +RUN apt-get update && \ + apt-get install -y curl unzip && \ + curl -O https://downloads.rclone.org/rclone-current-linux-amd64.zip && \ + unzip rclone-current-linux-amd64.zip && \ + cp rclone-*/rclone /usr/bin/ && \ + chmod 755 /usr/bin/rclone && \ + rm -rf rclone-* && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Create config directory +RUN mkdir -p /root/.config/rclone + +# Default command +CMD ["sh", "/backup.sh"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7562841 --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +# Backup Service + +Централизованный сервис для резервного копирования баз данных всех окружений (prod, tqo, eks). + +## Возможности + +- Автоматическое резервное копирование каждые 12 часов +- Сжатие бэкапов с помощью gzip +- Загрузка в S3 (Selectel) через rclone +- Раздельное хранение бэкапов по окружениям +- Автоматическая ротация (хранение последних 7 бэкапов) + +## Структура каталогов + +``` +backup_service/ +├── docker-compose.yml # Конфигурация Docker Compose +├── Dockerfile.backup # Docker образ с rclone +├── .env # Переменные окружения (создать из .env.example) +├── scripts/ +│ └── backup-db.sh # Скрипт резервного копирования +└── configs/ + └── rclone.conf # Конфигурация rclone для S3 +``` + +## Установка и запуск + +1. Скопируйте `.env.example` в `.env` и укажите пароли MySQL для каждого окружения: +```bash +cp .env.example .env +# Отредактируйте .env и укажите реальные пароли +``` + +2. Убедитесь, что сети Docker существуют: +```bash +docker network ls | grep -E "prod_dd|tqo_dd|eks_dd" +``` + +3. Соберите Docker образ: +```bash +docker-compose build +``` + +4. Запустите нужные сервисы: +```bash +# Запуск всех бэкапов +docker-compose up -d + +# Или запуск только для конкретного окружения +docker-compose up -d backup-prod +docker-compose up -d backup-tqo +docker-compose up -d backup-eks +``` + +## Мониторинг + +Просмотр логов: +```bash +# Все сервисы +docker-compose logs -f + +# Конкретное окружение +docker-compose logs -f backup-prod +``` + +## Расположение бэкапов + +### Локальные бэкапы +- Prod: `mysql_backup_volume_prod` +- TQO: `mysql_backup_volume_tqo` +- EKS: `mysql_backup_volume_eks` + +### S3 (Selectel) +- Prod: `selectel:backup_db/dot/prod/` +- TQO: `selectel:backup_db/dot/tqo/` +- EKS: `selectel:backup_db/dot/eks/` + +## Формат имен файлов + +Бэкапы сохраняются в формате: `{database_name}.{day_of_week}.sql.gz` + +Например: +- `mydatabase.Mon.sql.gz` +- `mydatabase.Tue.sql.gz` + +## Ручной запуск бэкапа + +Для немедленного создания бэкапа: +```bash +docker-compose exec backup-prod sh -c "kill 1" +# Контейнер перезапустится и сразу начнет бэкап +``` + +## Восстановление из бэкапа + +1. Скачайте бэкап из S3 или найдите в локальном volume +2. Распакуйте: +```bash +gunzip database.Mon.sql.gz +``` +3. Восстановите: +```bash +mysql -h hostname -u root -p database_name < database.Mon.sql +``` \ No newline at end of file diff --git a/scripts/backup-db.sh b/scripts/backup-db.sh new file mode 100644 index 0000000..838804e --- /dev/null +++ b/scripts/backup-db.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# Database backup script with S3 upload +# Runs every 12 hours and keeps last 7 local backups + +BACKUP_DIR="/backups" +DB_HOST="${DB_HOST:-db}" +DB_USER="${DB_USER:-root}" +DB_PASSWORD="${MYSQL_ROOT_PASSWORD}" +KEEP_BACKUPS="${KEEP_BACKUPS:-7}" +S3_BUCKET="${S3_BUCKET:-selectel:backup_db}" +S3_PATH="${S3_PATH:-dot}" +ENVIRONMENT="${ENVIRONMENT:-prod}" + +while true; do + echo "[$(date)] Starting database backup process..." + + # Get list of databases (exclude system databases) + DATABASES=$(mysql -h "${DB_HOST}" -u"${DB_USER}" -p"${DB_PASSWORD}" -s -AN -e 'show databases' | grep -vE "information_schema|performance_schema|sys|mysql") + + if [ $? -ne 0 ]; then + echo "[$(date)] ERROR: Failed to get database list!" + sleep 43200 + continue + fi + + # Backup each database separately + for database in ${DATABASES}; do + TIMESTAMP=$(date +%Y%m%d_%H%M%S) + DAY_NAME=$(date +%a) + BACKUP_FILE="${BACKUP_DIR}/${database}.${DAY_NAME}.sql.gz" + + echo "[$(date)] Backing up database: ${database}..." + + # Create backup with compression + mysqldump -h "${DB_HOST}" \ + -u"${DB_USER}" \ + -p"${DB_PASSWORD}" \ + --max-allowed-packet=1G \ + --add-drop-table \ + --single-transaction \ + --extended-insert \ + --quick \ + --lock-tables=false \ + "${database}" | gzip -c > "${BACKUP_FILE}" + + if [ $? -eq 0 ]; then + # Get file size for logging + BACKUP_SIZE=$(du -h "${BACKUP_FILE}" | cut -f1) + echo "[$(date)] Backup completed: ${database} (${BACKUP_SIZE})" + + # Upload to S3 if rclone is configured + if [ -f /root/.config/rclone/rclone.conf ]; then + echo "[$(date)] Uploading ${database} to S3..." + rclone copy "${BACKUP_FILE}" "${S3_BUCKET}/${S3_PATH}/${ENVIRONMENT}/" --progress + + if [ $? -eq 0 ]; then + echo "[$(date)] Successfully uploaded ${database} to S3" + # Optional: remove local backup after successful upload + # rm -f "${BACKUP_FILE}" + else + echo "[$(date)] WARNING: Failed to upload ${database} to S3" + fi + else + echo "[$(date)] Rclone not configured, keeping backup locally only" + fi + else + echo "[$(date)] ERROR: Failed to backup ${database}!" + [ -f "${BACKUP_FILE}" ] && rm -f "${BACKUP_FILE}" + fi + done + + # Clean old local backups (keep last N days for each database) + echo "[$(date)] Cleaning old local backups..." + for database in ${DATABASES}; do + ls -t ${BACKUP_DIR}/${database}.*.sql.gz 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) | xargs -r rm -f + done + + # List current backups + echo "[$(date)] Current local backups:" + ls -lah ${BACKUP_DIR}/*.sql.gz 2>/dev/null || echo "No backups found" + + echo "[$(date)] Next backup will run in 12 hours..." + echo "=========================================" + + # Sleep for 12 hours (43200 seconds) + sleep 43200 +done \ No newline at end of file