Переход с самописного бэкапа на нормальный инструмент
Если резервное копирование у вас — это tar czf в cron раз в сутки и письмо «бэкап готов», рано или поздно наступит момент, когда архив понадобится всерьез, а он не развернётся. Скрипт годами отрабатывал без единой ошибки — просто потому, что он и не умел эти ошибки замечать. Дальше — честный разбор, чем самописный подход хуже специализированного инструмента резервного копирования и как перейти на него, не рискуя тем немногим, что уже работает.
Содержание
- Что вообще такое «самописный бэкап» и чем он плох не по злому умыслу
- Ограничение №1: нет проверки целостности — «отработал без ошибок» не значит «восстановится»
- Ограничение №2: нет дедупликации и инкрементальности — каждый раз архивируем всё заново
- Ограничение №3: нет шифрования «из коробки» — риск при утечке самого архива
- Ограничение №4: нет гибкой политики хранения версий
- План перехода: как не потерять данные в процессе смены схемы
Что вообще такое «самописный бэкап» и чем он плох не по злому умыслу
Типичная схема выглядит примерно так:
#!/bin/bash
# /usr/local/bin/backup.sh
DATE=$(date +%Y%m%d)
tar czf /backup/site-$DATE.tar.gz /var/www/site
mysqldump myapp | gzip > /backup/db-$DATE.sql.gz
find /backup -mtime +30 -delete
И в cron:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Написать такой скрипт — час работы, и первое время он полностью закрывает потребность. Проблема не в том, что он «плохо написан» — часто это вполне аккуратный shell-код. Проблема в том, что он решает узкую задачу «создать файл-архив», а не задачу «дать возможность восстановиться». Это разные задачи, и разница между ними не видна, пока не случится реальный сбой. Специализированные инструменты резервного копирования (о них ниже) изначально построены вокруг второй задачи — восстановления, а не вокруг факта существования архива.
Дальше — четыре конкретных ограничения, из-за которых самописная схема рано или поздно упирается в потолок.
Ограничение №1: нет проверки целостности — «отработал без ошибок» не значит «восстановится»
tar в примере выше вернёт код завершения 0 почти при любых обстоятельствах, кроме совсем грубого сбоя. Он не знает и не проверяет:
- что архив не оборвался на середине из-за нехватки места на диске (
tarпри этом иногда пишет предупреждение в stderr, но если вы не парсите вывод построчно — оно тонет в логе); - что база данных не была залочена или не находилась в промежуточном состоянии в момент
mysqldump, из-за чего дамп логически противоречив; - что сам файл-архив не побился при копировании на другое хранилище (сеть, диск, переполнение — источников битых байт достаточно);
- что из архива вообще можно развернуть работающую систему, а не просто «файлы, похожие на нужные».
Все, что умеет типичный самописный скрипт — проверить код возврата команды. Это необходимое, но недостаточное условие. Есть отдельная статья о том, как выглядит на практике бэкап, который год исправно шёл и оказался нерабочим — это ровно тот сценарий, который проверка целостности должна ловить, но самописный tar её просто не делает.
Специализированные инструменты (BorgBackup, restic, Duplicati, Percona XtraBackup для баз данных и другие в этом классе) обычно вычисляют контрольные суммы блоков при создании бэкапа и умеют проверять консистентность репозитория командой вроде borg check или restic check — без разворачивания всего архива. Это не гарантия «данные точно нужные», но это гарантия «архив физически цел и читаем», чего самописный tar не даёт вовсе.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверОграничение №2: нет дедупликации и инкрементальности — каждый раз архивируем всё заново
Самописный tar czf в примере выше делает полный (full) бэкап каждую ночь. Если у вас 200 ГБ данных и меняется из них реально 500 МБ в день, вы всё равно:
- жмёте и записываете все 200 ГБ каждый раз;
- тратите на это время (при не самом быстром диске полный проход по 200 ГБ — это не секунды);
- храните N полных копий почти без пользы: 30 дней хранения при
find -mtime +30 -delete— это 30 * 200 ГБ места, из которых реально уникальных данных — доли процента.
Можно, конечно, усложнить самописный скрипт до инкрементальных бэкапов через tar --listed-incremental, но тогда вы фактически начинаете писать свою версию специализированного инструмента — с той разницей, что деduplication (устранение повторяющихся блоков данных не только между полным и инкрементальным бэкапом, а вообще между любыми файлами в репозитории) руками не пишут, это отдельный алгоритмический слой.
Специализированные инструменты резервного копирования с дедупликацией на уровне блоков (не файлов) хранят один и тот же неизменившийся блок данных один раз, даже если он встречается в тысяче версий файла. На типичной нагрузке (логи, конфиги, базы данных с умеренной скоростью изменений) это даёт существенную экономию места по сравнению с хранением N полных копий — точную цифру для вашего случая никто не назовёт заранее, она зависит от того, как часто и как сильно меняются ваши данные, но направление эффекта устойчиво воспроизводится.
Сравнение подхода к хранению:
Самописный tar full-бэкап | Специализированный инструмент с дедупликацией | |
|---|---|---|
| Что архивируется каждый раз | Все данные целиком | Только изменившиеся блоки |
| Место на диске при хранении истории | Растёт линейно с числом копий | Растёт вместе с объёмом реальных изменений |
| Время на бэкап | Пропорционально полному объёму данных | Пропорционально объёму изменений |
| Проверка целостности | Отсутствует | Встроенная команда проверки репозитория |
| Шифрование архива | Обычно отсутствует | Обычно есть «из коробки» |
| Политика хранения версий | Пишете руками (find -mtime) | Настраиваемые правила ротации (retention policy) |
Ограничение №3: нет шифрования «из коробки» — риск при утечке самого архива
Файл /backup/db-20260904.sql.gz в примере выше лежит на диске в открытом виде. Это не проблема, пока к серверу и к хранилищу бэкапов имеют доступ только те, кому положено. Но как только архив копируется куда-то ещё — на внешнее хранилище, на другой сервер, в облако, на съёмный диск, — вы фактически создаёте вторую копию всех ваших данных без того контроля доступа, который есть у продакшен-базы. Если это хранилище скомпрометировано (неправильные права на S3-бакет, украденный диск, скомпрометированный промежуточный сервер), утечёт всё содержимое бэкапа целиком и без всяких усилий со стороны атакующего — расшифровывать нечего, там открытый текст.
Дописать шифрование к самописному скрипту вроде бы просто — gpg --symmetric или openssl enc перед записью на диск. Но здесь возникает ключевой вопрос: где хранить ключ или пароль расшифровки, отдельно от самого сервера, и как ротировать его при компрометации. Это уже не одна строчка, а отдельная подсистема управления секретами. У специализированных инструментов шифрование обычно встроено на уровне репозитория — ключ задаётся один раз при инициализации, и дальше каждый чанк данных шифруется автоматически перед отправкой на любое хранилище, включая недоверенное (тот же принцип, что и в статье про настройку бэкапа с шифрованием на VPS). Разница практическая: ключ для шифрования вы обязаны хранить сами и отдельно от бэкапа в любом случае — инструмент не решает эту часть за вас, — но саму механику шифрования каждого блока вам не нужно писать и поддерживать руками.
Ограничение №4: нет гибкой политики хранения версий
В примере скрипта в начале статьи ротация — это find /backup -mtime +30 -delete: всё, что старше 30 дней, удаляется без разбора. У этого подхода два типичных исхода, и оба плохие:
- Хранить всё бесконечно (без
find -deleteвообще) — тогда диск на бэкапы рано или поздно кончается, и вы узнаёте об этом в худший момент — когда бэкап очередной ночи не смог записаться, потому что места не осталось, а вы это заметили только через неделю. Разбор похожего сценария — в статье диск заполнился на 100%: что отвалилось первым. - Тупо стирать всё старше N дней — тогда вы теряете возможность откатиться на состояние месячной или годовой давности, если проблема (например, повреждение данных приложением) была внесена давно и обнаружена поздно. Классический пример — постепенно нарастающая порча данных, которую заметили только через два месяца, когда все версии за эти два месяца уже стёрты.
Специализированные инструменты обычно реализуют многоуровневую политику хранения (retention policy) вроде «храни последние 7 ежедневных, 4 еженедельных, 12 ежемесячных версий» одной командой — без ручного перебора файлов по дате создания. Это не только про место на диске, но и про реальную возможность вернуться на нужную точку во времени, а не только «на вчера».
План перехода: как не потерять данные в процессе смены схемы
Дальше — практическая последовательность действий. Ключевая идея: старая схема не выключается, пока новая не доказала надёжность. Слишком часто переход выглядит как «поставили новое, удалили cron-задачу со старым скриптом в тот же день» — и именно в эту неделю новая схема обнаруживает свой первый баг.
Шаг 1. Выбор инструмента под задачу
Не привязываясь к конкретному продукту и версии — на рынке есть отдельный класс специализированных инструментов резервного копирования с дедупликацией на уровне блоков, встроенным шифрованием и гибкой ротацией версий. Разные инструменты из этого класса различаются по тому, синхронный ли клиент-сервер у них или push-модель с клиента, какие протоколы хранилищ поддерживают (локальный диск, SFTP, S3-совместимое хранилище), и насколько тонко настраивается retention. Сравнение конкретных пар инструментов между собой — тема отдельных статей, например restic или BorgBackup: что выгоднее и когда или MinIO или UrBackup: что выгоднее и когда. Для файлов и конфигов подойдёт один класс инструментов, для баз данных под нагрузкой — специализированные средства вроде тех, что описаны в статье про резервное копирование баз данных: дамп «на живую» через mysqldump без блокировок может давать логически несогласованный результат под нагрузкой, и там нужны другие механизмы снятия консистентного снапшота.
Шаг 2. Настройка нового инструмента параллельно со старым — переходный период
Не отключайте cron-задачу со старым скриптом. На переходный период (обычно 2-4 недели, но ориентируйтесь на реальный цикл ваших изменений данных) обе схемы работают одновременно:
# старый скрипт остаётся как есть
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# новый инструмент — на отдельное время, чтобы не спорить за диск и I/O
0 4 * * * /usr/local/bin/new-backup-run.sh >> /var/log/new-backup.log 2>&1
Смысл в том, что если новый инструмент неправильно настроен (не тот путь, не та база, забытый чанк конфигурации), у вас всё ещё есть рабочий старый бэкап, пока вы это не обнаружите и не исправите. Отключать старую схему раньше времени — это ставить весь процесс перехода на кон при первом же незамеченном сбое новой.
В этот период также стоит явно сверить объём и состав данных между старым и новым бэкапом — не «оба отработали без ошибок», а конкретно: те же ли базы данных попали в бэкап, тот же ли набор директорий, не пропущен ли какой-то том или каталог, который был в старом скрипте по историческим причинам.
Шаг 3. Обязательное тестовое восстановление — не просто «бэкап создался»
Это самый пропускаемый шаг, и именно он определяет, доверяете вы новой схеме реально или на слово. «Бэкап создался без ошибок» ничего не говорит о том, разворачивается ли он в рабочее состояние — то же самое ограничение, из-за которого вы, собственно, и уходите от самописного скрипта.
Практический минимум тестового восстановления:
- Разверните новый экземпляр (тестовый сервер или временный контейнер) отдельно от продакшена.
- Восстановите на него данные именно из нового бэкап-инструмента:
borg extract,restic restore,urbackupчерез веб-интерфейс восстановления — в зависимости от выбранного инструмента. - Поднимите приложение/базу на восстановленных данных и проверьте, что оно реально стартует и отдаёт корректные данные — не просто «файлы на месте», а рабочий сервис.
- Для баз данных отдельно проверьте логическую целостность: количество строк в ключевых таблицах, отсутствие ошибок при
CHECK TABLEили аналоге для вашей СУБД. - Зафиксируйте время, которое ушло на весь цикл восстановления — это ваш ориентировочный RTO (recovery time objective), и без реального теста вы его просто не знаете, а строите предположения. Разбор того, как на практике выглядит восстановление базы данных из бэкапа, хорошо показывает, где обычно всплывают неожиданности — не в самом восстановлении файла, а в шагах после него (миграции схемы, переменные окружения, права доступа).
Только после того, как тестовое восстановление прошло успешно несколько раз подряд (не один случайный успех — воспроизводимость важнее одного факта), и вы прогнали новую схему параллельно со старой достаточно циклов, чтобы увидеть её поведение на реальных данных — можно отключать старый скрипт. И даже тогда разумно оставить его код в репозитории на случай, если новый инструмент откажет по неожиданной причине — это не откат к самописной схеме навсегда, а страховка на один-два цикла, пока разбираетесь.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли просто дописать проверку целостности и шифрование к своему скрипту, а не переходить на отдельный инструмент?
Технически да, но на практике вы в этот момент начинаете писать урезанную версию того, что уже реализовано, протестировано и поддерживается в специализированных инструментах — дедупликацию на уровне блоков, безопасное управление ключами шифрования, атомарную ротацию версий. Если задача разовая и данных немного, доработать скрипт может быть оправдано. Если данных много и они растут — трудозатраты на поддержку самописной логики со временем перевешивают трудозатраты на изучение готового инструмента.
Сколько времени занимает сам переход?
Настройка нового инструмента — от часа до дня в зависимости от объёма данных и числа источников (базы, файлы, конфиги). Переходный период параллельной работы обеих схем — обычно 2-4 недели, ориентируйтесь на то, чтобы застать хотя бы один полный цикл ваших типичных изменений данных (например, если у вас есть периодическая тяжёлая операция раз в неделю — дождитесь её).
Что делать, если специализированный инструмент тоже не проходит тестовое восстановление?
Не переключайтесь. Останьтесь на старой схеме, разберитесь в причине (чаще всего — неверная конфигурация путей или прав доступа, а не проблема самого инструмента), повторите тест. Тестовое восстановление ровно для того и существует, чтобы такие вещи всплывали до того, как старая схема отключена, а не после.
Нужен ли отдельный сервер под бэкапы или можно хранить их локально?
Хранение бэкапа на том же физическом сервере, что и оригинальные данные, — отдельная и частая ошибка, не связанная напрямую с выбором инструмента: при отказе диска или всего сервера теряются одновременно и данные, и их резервная копия. Это разобрано в статье антипаттерн: бэкап на том же сервере. Независимо от инструмента бэкапа копия должна физически находиться на другом сервере или ином хранилище.
Дедупликация не увеличивает риск — если испортится один общий блок, не пострадают ли сразу все версии, которые на него ссылаются?
Разумное опасение, поэтому специализированные инструменты дополняют дедупликацию проверкой целостности репозитория (contol-суммы блоков) и обычно позволяют держать резервную копию самого репозитория бэкапов отдельно. Дедупликация экономит место, но не отменяет необходимость иметь больше одной физической копии архива в принципе — это не взаимоисключающие меры, а разные уровни защиты.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →