Restic + S3: автоматический бэкап с дедупликацией

Почему Restic для корпоративных бэкапов

Restic — инструмент резервного копирования на Go. Три вещи выделяют его среди конкурентов: дедупликация на уровне блоков (одинаковые данные физически хранятся один раз), шифрование по умолчанию — никаких отдельных плагинов, всё включено (AES-256-CTR + Poly1305-AES) — и поддержка множества бэкендов: локальные диски, S3, SFTP, Azure Blob, Google Cloud Storage. Поставил и работаешь.

Если честно, именно для ИТ-отделов небольших компаний это сочетание оказывается очень удачным. Инкрементальные бэкапы почти не занимают места — за счёт content-defined chunking (CDC) дублирующиеся блоки не пишутся повторно. При этом каждый снапшот — полноценная точка восстановления, не нужно прогонять всю цепочку инкрементов как в старых решениях. Ну и выбор по хранилищам широкий: поднять собственный MinIO или подключить Yandex Object Storage — дело получаса.

В этой статье разберём, как настроить автоматическое резервное копирование серверов в S3 — с ротацией снапшотов, мониторингом и оповещениями, когда что-то пошло не так.

Установка Restic и инициализация репозитория

Ставим Restic из официального репозитория:

# Ubuntu/Debian
sudo apt install -y restic

# Или скачиваем последнюю версию
wget https://github.com/restic/restic/releases/download/v0.16.4/restic_0.16.4_linux_amd64.bz2
bunzip2 restic_0.16.4_linux_amd64.bz2
sudo mv restic_0.16.4_linux_amd64 /usr/local/bin/restic
sudo chmod +x /usr/local/bin/restic

# Проверяем
restic version

Прописываем переменные окружения для доступа к S3:

# /etc/restic/env.sh
export RESTIC_REPOSITORY="s3:https://storage.yandexcloud.net/company-backups"
export RESTIC_PASSWORD="SuperSecretEncryptionKey2024"
export AWS_ACCESS_KEY_ID="YCAJExxxxxxxxxxxxxxxxx"
export AWS_SECRET_ACCESS_KEY="YCPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Инициализируем репозиторий:

source /etc/restic/env.sh
restic init

Если используете MinIO — endpoint задаётся в формате s3:http://minio.company.ru:9000/backups.

Безопасное хранение credentials

Файл с переменными должен читать только root — никаких исключений:

sudo mkdir -p /etc/restic
sudo chmod 700 /etc/restic
sudo chmod 600 /etc/restic/env.sh

Пароль репозитория можно вынести в отдельный файл: RESTIC_PASSWORD_FILE=/etc/restic/password. Но вот что действительно важно помнить: сменить пароль шифрования без пересоздания репозитория невозможно. Мы сталкивались с ситуациями, когда люди хотели это сделать задним числом — не вышло. Выбирайте нормальный пароль сразу.

Создание бэкапов: файлы, базы данных, конфигурации

Базовая команда для запуска бэкапа:

# Бэкап директорий
restic backup /etc /home /var/www /opt/apps \
    --exclude="*.tmp" \
    --exclude="*.log" \
    --exclude=".cache" \
    --tag server=web-01 \
    --tag type=files

Для бэкапа баз данных сначала снимаем дамп, потом уже кладём его в restic:

# PostgreSQL
pg_dumpall -U postgres | restic backup --stdin --stdin-filename pg_dumpall.sql --tag type=database

# MySQL/MariaDB
mysqldump --all-databases --single-transaction | restic backup --stdin --stdin-filename mysql_all.sql --tag type=database

# Можно комбинировать в одном снапшоте
mkdir -p /tmp/db-dumps
pg_dumpall -U postgres > /tmp/db-dumps/postgres.sql
mongodump --out /tmp/db-dumps/mongo/
restic backup /tmp/db-dumps --tag type=database --tag server=db-01
rm -rf /tmp/db-dumps

Restic сам разбирается, что изменилось с прошлого раза. Первый бэкап — полный, всё копируется. Дальше — только дельта. При этом каждый снапшот остаётся самодостаточной точкой восстановления: не нужно ничего «склеивать».

Автоматизация через systemd-таймеры

Создаём systemd-сервис /etc/systemd/system/restic-backup.service:

[Unit]
Description=Restic Backup
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env.sh
ExecStartPre=/usr/local/bin/restic-pre-backup.sh
ExecStart=/usr/local/bin/restic backup /etc /home /var/www /opt --exclude-file=/etc/restic/excludes.txt --tag server=%H --tag type=files
ExecStartPost=/usr/local/bin/restic-post-backup.sh
Nice=19
IOSchedulingClass=idle

Таймер /etc/systemd/system/restic-backup.timer:

[Unit]
Description=Run Restic Backup daily

[Timer]
OnCalendar=*-*-* 02:00:00
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target

Активируем и запускаем:

sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl list-timers | grep restic

Скрипт pre/post-backup

Скрипт /usr/local/bin/restic-pre-backup.sh отрабатывает перед бэкапом — здесь удобно снимать дампы БД:

#!/bin/bash
set -euo pipefail
mkdir -p /var/backups/db
pg_dumpall -U postgres > /var/backups/db/postgres.sql 2>/var/log/restic-pre.log
echo "Pre-backup completed at $(date)" >> /var/log/restic-pre.log

Скрипт /usr/local/bin/restic-post-backup.sh запускается после — чистим временные файлы и отправляем уведомление:

#!/bin/bash
set -euo pipefail
source /etc/restic/env.sh

# Очистка дампов
rm -rf /var/backups/db

# Проверка целостности (раз в неделю)
if [ "$(date +%u)" -eq 7 ]; then
    restic check --read-data-subset=5% 2>&1 | logger -t restic-check
fi

# Уведомление об успехе
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
    -d chat_id="${TG_CHAT}" \
    -d text="Backup OK: $(hostname) at $(date '+%Y-%m-%d %H:%M')"

Политика ротации снапшотов

Ротация в Restic гибкая. Управляется через команду forget с набором флагов политики хранения:

# Оставляем: 7 ежедневных, 4 еженедельных, 12 ежемесячных, 2 годовых
restic forget \
    --keep-daily 7 \
    --keep-weekly 4 \
    --keep-monthly 12 \
    --keep-yearly 2 \
    --prune \
    --tag server=web-01

Флаг --prune удаляет данные сразу — те блоки, на которые больше не ссылается ни один снапшот. Без него forget только помечает снапшоты, но место на диске не освобождается. Путаница с этим моментом встречается часто — имейте в виду.

Для автоматической ротации добавьте в systemd-сервис:

ExecStartPost=/usr/local/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 2 --prune

Команда prune — не лёгкая операция. Она перепаковывает pack-файлы, и на больших репозиториях (от нескольких десятков ТБ) это серьёзная нагрузка на сеть и CPU. Спасает флаг --max-repack-size 5G: он ограничивает объём перепаковки за один запуск, и процесс не превращается в многочасовую пытку для инфраструктуры.

Восстановление данных из бэкапа

Смотрим список доступных снапшотов:

# Все снапшоты
restic snapshots

# Фильтр по тегу
restic snapshots --tag server=web-01

# Фильтр по дате
restic snapshots --tag type=files | head -20

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

# Полное восстановление в указанную директорию
restic restore latest --target /tmp/restore

# Восстановление конкретного снапшота
restic restore abc12345 --target /tmp/restore

# Восстановление отдельных файлов
restic restore latest --target /tmp/restore --include "/etc/nginx"

# Монтирование как FUSE-файловой системы
mkdir -p /mnt/restic
restic mount /mnt/restic &
# Снапшоты доступны как директории
ls /mnt/restic/snapshots/

FUSE-монтирование — штука реально удобная. Все снапшоты видны как обычные директории, нужный файл вытаскиваешь стандартным cp, не разворачивая весь бэкап. Сэкономили так не один час на точечном восстановлении у клиентов.

Мониторинг и проверка целостности

В Restic есть встроенная проверка целостности репозитория — пользуйтесь:

# Быстрая проверка метаданных
restic check

# Полная проверка с чтением данных
restic check --read-data

# Проверка части данных (для больших репозиториев)
restic check --read-data-subset=10%

Чтобы отслеживать размер репозитория и факт успешного прохождения бэкапов, напишем скрипт для Zabbix/Prometheus:

#!/bin/bash
# /usr/local/bin/restic-metrics.sh
source /etc/restic/env.sh

# Время последнего снапшота (Unix timestamp)
LAST_SNAP=$(restic snapshots --json --latest 1 | jq '.[0].time' -r)
LAST_TS=$(date -d "$LAST_SNAP" +%s)
NOW=$(date +%s)
AGE_HOURS=$(( (NOW - LAST_TS) / 3600 ))

# Статистика репозитория
STATS=$(restic stats --json)
TOTAL_SIZE=$(echo $STATS | jq '.total_size')
SNAP_COUNT=$(restic snapshots --json | jq 'length')

echo "restic_last_backup_age_hours $AGE_HOURS"
echo "restic_total_size_bytes $TOTAL_SIZE"
echo "restic_snapshot_count $SNAP_COUNT"

Настройте алерт по простому условию: если restic_last_backup_age_hours > 26 — ночной бэкап не прошёл. 26 часов с запасом перекрывают возможные задержки, но при этом не позволяют пропустить реальный сбой.

Часто задаваемые вопросы

Да, безопасно. Restic шифрует и данные, и метаданные ещё до отправки в хранилище (AES-256). Провайдер на своей стороне видит только зашифрованные blob-файлы — без пароля репозитория это просто набор байт. Дополнительно стоит закрыть бакет политикой IAM, чтобы ограничить доступ на уровне облака.

Несколько параметров, которые реально помогают. Параметр --read-concurrency включает параллельное чтение, -o s3.connections=20 поднимает число одновременных соединений с S3. Отдельно — кеш: --cache-dir /var/cache/restic хранит метаданные локально и заметно ускоряет повторные бэкапы. На крупных репозиториях разница ощутимая.

Да, нативная сборка под Windows есть. Поддерживается VSS (Volume Shadow Copy) — это значит, можно бэкапить открытые файлы без остановки приложений. Запускать удобно через Task Scheduler или завернуть логику в PowerShell-скрипт.

Restic атомарен. Если бэкап прервался посередине — незавершённый снапшот просто не появится в списке. При следующем запуске процесс стартует заново, но уже загруженные блоки повторно не передаются — дедупликация делает своё дело.

Нужна помощь с настройкой?

Команда АйТи Фреш поможет внедрить и настроить резервное копирование под вашу инфраструктуру — 15+ лет в ИТ-аутсорсинге, обслуживание от 15 000 ₽/мес.

📞 Связаться с нами
#restic backup#резервное копирование s3#restic настройка#дедупликация бэкапов#автоматический бэкап linux#restic minio#бэкап сервера#restic ротация
Комментарии 0

Оставить комментарий

загрузка...