Содержание
- Три способа, которыми ломается бэкап
- Шаг 1: Создайте канал, способный привлечь внимание
- Шаг 2: Ловите сбои скриптом-обёрткой
- borg и borgmatic
- Шаг 3: Ловите бэкап, который не запускался
- Шаг 4: Проверьте, что бэкап свежий и восстановимый
- Шаг 5: Звоните только когда это важно
- Частые вопросы
- Как получить уведомление о сбое бэкапа?
- На какие коды завершения restic стоит оповещать?
- Как понять, что бэкап молча перестал запускаться?
- Достаточно ли успешного кода завершения, чтобы доверять бэкапу?
- Можно ли получать звонок вместо письма?
- Итог
- Похожие статьи
Большинство людей узнаёт, что бэкапы не работали, в тот самый день, когда они нужны. Задача завершилась с ошибкой три недели назад, никто не читал лог, а свежий снапшот старше ошибки, которую вы пытаетесь отменить.
Решение — не в лучшем инструменте для бэкапа, а в том, чтобы проблема доходила до человека в тот же час, когда случилась. В этом руководстве показано, как это сделать для restic и borg (и всего, что запускается из shell): три реальных способа, которыми ломаются бэкапы, и скрипты, которые можно скопировать. На последнем шаге алерт уходит на телефон через Echobell, так что сломанный бэкап звонит, а не лежит в почтовом ящике.
Три способа, которыми ломается бэкап
Самая частая ошибка — следить только за первым.
- Запустился и упал. Репозиторий заблокирован, диск заполнен, неверный пароль, обрыв сети. Инструмент завершается с ненулевым кодом.
- Запустился и выполнился наполовину. restic завершается с кодом
3, если снапшот создан, но часть файлов прочитать не удалось. borg возвращает1при предупреждениях. Оба случая легко списать со счетов, и оба могут скрывать проблему с правами доступа, из-за которой молча пропускается самый важный каталог. - Не запустился вообще. Сервер был выключен, таймер отключён, crontab перезаписан. Ошибки нет, потому что нет процесса. Именно этот сбой и убивает.
Для каждого нужен свой детектор, поэтому мы построим все три.
Шаг 1: Создайте канал, способный привлечь внимание
В Echobell создайте канал backups и для важных задач выберите тип уведомления Звонок. Скопируйте его URL вебхука:
https://hook.echobell.one/t/<channel-token>
Задайте шаблоны, понятные спросонья, на основе полей, которые мы будем отправлять ниже:
Заголовок: Бэкап {{status}} на {{host}}
Текст: {{job}}: {{detail}}
Синтаксис описан в справочнике по шаблонам.
Шаг 2: Ловите сбои скриптом-обёрткой
Небольшая обёртка превращает коды завершения в алерты. Сохраните как /usr/local/bin/backup-run:
#!/usr/bin/env bash
set -uo pipefail
HOOK="https://hook.echobell.one/t/<channel-token>"
JOB="nightly-restic"
alert() {
curl -fsS -m 10 -X POST "$HOOK" \
-H "Content-Type: application/json" \
-d "{\"job\":\"$JOB\",\"host\":\"$(hostname)\",\"status\":\"$1\",\"detail\":\"$2\"}" || true
}
restic backup /srv /etc --exclude-caches
code=$?
case $code in
0) ;; # успех: молчим
3) alert "incomplete" "Snapshot saved, but some files were unreadable" ;;
11) alert "locked" "Repository is locked by another process" ;;
12) alert "auth-failed" "Wrong repository password" ;;
*) alert "failed" "restic exited with code $code" ;;
esac
exit $code
Почему важны детали:
set -eнамеренно не используется, чтобы скрипт дошёл до алерта после падения restic.|| trueуcurlозначает, что недоступный вебхук никогда не заменит настоящий код завершения.-m 10не даёт зависшему сетевому вызову заблокировать следующий запланированный запуск.
Коды завершения restic, использованные выше, описаны в руководстве restic: 0 — успех, 1 — фатальная ошибка, 3 — снапшот создан, но часть исходных файлов не читается, 10 — репозиторий не существует, 11 — не удалось заблокировать, 12 — неверный пароль. Сверьтесь с restic version на своей машине: коды добавлялись со временем.
borg и borgmatic
borg возвращает 0 при успехе, 1 при предупреждениях и 2 и выше при ошибках. Изменение файла во время бэкапа даёт 1, что для каталогов с логами обычное дело, поэтому распространённый подход — звонить только при 2 и выше, а для 1 отправлять тихое уведомление:
borg create --stats ::'{hostname}-{now}' /srv /etc
code=$?
if [ "$code" -ge 2 ]; then
alert "failed" "borg exited with code $code"
elif [ "$code" -eq 1 ]; then
alert "warning" "borg finished with warnings"
fi
Если вы используете borgmatic, его хук on_error запускает команду, когда ошибка возникает в самом borgmatic, — естественное место для того же curl. Учтите ограничение, которое признаёт и документация borgmatic: если borgmatic вообще не запустился, on_error не сработает. Это сбой номер три, и для него нужен шаг 3.
Шаг 3: Ловите бэкап, который не запускался
Обёртка может сообщить только о запуске, который состоялся. Чтобы поймать тишину, переверните логику: бэкап отправляет ping в монитор при успехе, а монитор оповещает вас, когда ping опаздывает. Это называется dead man's switch («выключатель мертвеца»).
Healthchecks.io (облачный или собственный) делает именно это:
- Создайте проверку с расписанием
0 3 * * *и льготным временем в час-два. - Добавьте её ping в конец задачи, чтобы он срабатывал только при успехе.
- В интеграциях проверки добавьте Webhook на URL вашего канала Echobell.
Ping ставится в конец обёртки:
# в backup-run прямо перед финальным `exit $code`; пингует только при успехе
if [ $code -eq 0 ]; then
curl -fsS -m 10 --retry 3 -o /dev/null https://hc-ping.com/<your-uuid>
fi
Healthchecks также поддерживает варианты ping /start и /fail и умеет принимать код завершения в URL, так что одна проверка поймает и зависшие задачи. Итог: умерший сервер, отключённый таймер и удалённая строка crontab приводят к одному результату — звонит телефон. Общую схему и другие мониторы смотрите в статье оповещения о сбоях cron-задач.
Шаг 4: Проверьте, что бэкап свежий и восстановимый
Бэкап может выполняться по расписанию, завершаться с кодом 0 и всё равно быть бесполезным — например, если после сбоя монтирования вы копируете пустой каталог. Добавьте две недорогие проверки в отдельную ежедневную задачу:
Возраст снапшота. Оповещайте, если самый свежий снапшот старше ожидаемого:
latest=$(restic snapshots --latest 1 --json | jq -r '.[0].time')
age_h=$(( ( $(date +%s) - $(date -d "$latest" +%s) ) / 3600 ))
if [ "$age_h" -gt 30 ]; then
alert "stale" "Newest snapshot is ${age_h}h old"
fi
Целостность репозитория. restic check проверяет структуру репозитория. Запускайте его раз в неделю; для больших репозиториев restic check --read-data-subset=5% проверяет выборку данных, не читая всё. Оповещайте при ненулевом коде.
Ни то ни другое не заменяет настоящего тестового восстановления. Раз в квартал восстанавливайте проверяемый файл во временный каталог. Это единственный тест, который доказывает, что бэкап работает.
Шаг 5: Звоните только когда это важно
Если каждое предупреждение звонит вам на телефон, вы заглушите канал, и он не зазвонит в тот единственный раз, когда это важно. Используйте условия Echobell, чтобы разделить уровни в одном канале:
status == "failed" || status == "stale" || status == "auth-failed"
Отправляйте incomplete и warning во второй канал — Срочное (Time Sensitive) или обычный: они появятся на экране блокировки без звонка. Если хотите, чтобы дневные сбои были тихими, добавьте временное окно с помощью UTC-переменных из справочника по условиям.
Частые вопросы
Как получить уведомление о сбое бэкапа?
Оберните команду бэкапа, прочитайте её код завершения и отправляйте вебхук при любом ненулевом коде. Добавьте dead man's switch вроде Healthchecks.io, чтобы узнавать и о запусках, которые не начались.
На какие коды завершения restic стоит оповещать?
Громко оповещайте на 1, 10, 11 и 12 — это настоящие сбои. Код 3 (снапшот создан, но часть файлов не читается) считайте предупреждением, которое нужно разобрать, поскольку он может скрывать проблему с правами.
Как понять, что бэкап молча перестал запускаться?
Используйте heartbeat: задача отправляет ping в монитор при успехе, а монитор оповещает, когда ping опаздывает. Хук ошибки здесь не поможет: ничего не запускается, значит, и ошибку поднимать некому.
Достаточно ли успешного кода завершения, чтобы доверять бэкапу?
Нет. Он означает лишь, что инструмент отработал, а не что данные полны или восстановимы. Проверяйте возраст снапшотов, периодически запускайте проверки целостности и регулярно тестируйте восстановление.
Можно ли получать звонок вместо письма?
Да. Письмо легко пропустить. Звонковый канал в Echobell ведёт себя как входящий вызов и проходит через режим фокусирования iOS, поэтому сбой бэкапа в 03:00 не останется незамеченным.
Итог
Три детектора закрывают три режима отказа: обёртка с кодами завершения — для запусков, которые падают; проверка свежести — для запусков, которые «успешны», но бесполезны; heartbeat — для запусков, которых не было. Направьте их в звонковый канал, оставьте предупреждения для более тихого — и сломанный бэкап превратится в пятиминутное исправление вместо потерянных выходных.
Скачайте Echobell для iPhone или возьмите в Google Play, создайте канал backups и запустите обёртку один раз с заведомо неверным паролем, чтобы услышать звонок.