Alertes d'échec de sauvegarde : savoir avant de restaurer

Les sauvegardes échouent en silence. Détectez erreurs restic/borg, snapshots périmés et exécutions manquées, et recevez un appel. Scripts à copier-coller.

Mis à jour

Table des matières

La plupart des gens découvrent que leurs sauvegardes étaient cassées le jour où ils en ont besoin. Le job s'est terminé en erreur il y a trois semaines, personne n'a lu le journal, et le snapshot le plus récent est plus ancien que l'erreur que vous essayez d'annuler.

La solution n'est pas un meilleur outil de sauvegarde. Il s'agit de faire en sorte qu'un problème de sauvegarde atteigne un humain dans l'heure où il se produit. Ce guide montre comment y parvenir pour restic et borg (et tout ce qui s'exécute depuis un shell), en couvrant les trois façons dont les sauvegardes échouent réellement, avec des scripts à copier. La dernière étape envoie l'alerte sur votre téléphone via Echobell : une sauvegarde cassée sonne au lieu de dormir dans une boîte mail.

Les trois façons dont une sauvegarde échoue

Ne surveiller que la première est l'erreur la plus courante.

  1. Elle s'exécute et échoue. Dépôt verrouillé, disque plein, mauvais mot de passe, coupure réseau. L'outil se termine avec un code non nul.
  2. Elle s'exécute et réussit à moitié. restic se termine avec le code 3 lorsqu'un snapshot a été créé mais que certains fichiers n'ont pas pu être lus. borg renvoie 1 pour les avertissements. Les deux sont faciles à balayer d'un revers de main, et les deux peuvent masquer un problème de permissions qui ignore en silence votre répertoire le plus important.
  3. Elle ne s'exécute jamais. Le serveur était éteint, le timer désactivé, la crontab écrasée. Il n'y a pas d'erreur car il n'y a pas de processus. C'est la panne qui coûte cher.

Chacune demande un détecteur différent : nous allons donc construire les trois.

Étape 1 : Créer un canal capable d'attirer votre attention

Dans Echobell, créez un canal nommé backups et réglez son type de notification sur Appel pour les jobs qui comptent. Copiez l'URL de son webhook :

https://hook.echobell.one/t/<channel-token>

Donnez-lui des modèles lisibles à moitié endormi, en utilisant les champs que nous enverrons plus bas :

Titre : Sauvegarde {{status}} sur {{host}}
Corps : {{job}} : {{detail}}

Consultez la référence des modèles pour la syntaxe.

Étape 2 : Détecter les échecs avec un script enveloppe

Un petit script enveloppe transforme les codes de sortie en alertes. Enregistrez-le sous /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)  ;;                                   # succès : rester silencieux
  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

Pourquoi les détails comptent :

  • set -e n'est volontairement pas utilisé, pour que le script atteigne l'alerte même après un échec de restic.
  • || true sur le curl garantit qu'un webhook injoignable ne masque jamais le vrai code de sortie.
  • -m 10 empêche un appel réseau bloqué de retarder la prochaine exécution planifiée.

Les codes de sortie de restic utilisés ci-dessus sont documentés dans le manuel de restic : 0 succès, 1 erreur fatale, 3 snapshot créé mais certains fichiers sources illisibles, 10 le dépôt n'existe pas, 11 échec du verrouillage, 12 mauvais mot de passe. Vérifiez-les avec restic version sur votre machine, car des codes ont été ajoutés au fil du temps.

borg et borgmatic

borg renvoie 0 en cas de succès, 1 pour les avertissements et 2 ou plus pour les erreurs. Un fichier qui change pendant la sauvegarde produit 1, ce qui est courant pour les répertoires de journaux ; une approche répandue consiste donc à n'alerter qu'à partir de 2 et à envoyer une notification discrète pour 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

Si vous utilisez borgmatic, son hook on_error exécute une commande lorsque borgmatic rencontre lui-même une erreur : c'est l'endroit naturel pour le même curl. Notez la limite que la documentation de borgmatic signale elle-même : si borgmatic ne s'exécute jamais, on_error ne se déclenche jamais. C'est la panne numéro trois, et elle demande l'étape 3.

Étape 3 : Détecter la sauvegarde qui ne s'est jamais exécutée

Un script enveloppe ne peut rendre compte que d'une exécution qui a eu lieu. Pour détecter le silence, inversez la logique : la sauvegarde envoie un ping à un moniteur quand elle réussit, et le moniteur vous alerte quand le ping est en retard. C'est ce qu'on appelle un dead man's switch (interrupteur d'homme mort).

Healthchecks.io (hébergé ou auto-hébergé) fait exactement cela :

  1. Créez un check avec le planning 0 3 * * * et un délai de grâce d'une ou deux heures.
  2. Ajoutez son ping à la fin de votre job pour qu'il ne parte qu'en cas de succès.
  3. Dans les intégrations du check, ajoutez un Webhook pointant vers l'URL de votre canal Echobell.

Le ping se place à la fin du script enveloppe :

# dans backup-run, juste avant le `exit $code` final ; ne pingue qu'en cas de succès
if [ $code -eq 0 ]; then
  curl -fsS -m 10 --retry 3 -o /dev/null https://hc-ping.com/<your-uuid>
fi

Healthchecks prend aussi en charge les variantes de ping /start et /fail et peut recevoir le code de sortie dans l'URL, si bien qu'un seul check peut aussi détecter les jobs bloqués. Résultat : un serveur mort, un timer désactivé et une ligne de crontab supprimée produisent tous le même effet, un téléphone qui sonne. Pour le schéma général et d'autres moniteurs, voir les alertes d'échec de tâches cron.

Étape 4 : Vérifier que la sauvegarde est récente et restaurable

Une sauvegarde peut s'exécuter à l'heure, se terminer avec 0 et rester inutile, par exemple quand vous sauvegardez un répertoire vide parce qu'un montage a échoué. Ajoutez deux contrôles de cohérence peu coûteux dans un job quotidien séparé :

Âge du snapshot. Alertez si le snapshot le plus récent est plus ancien que prévu :

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

Intégrité du dépôt. restic check vérifie la structure du dépôt. Lancez-le chaque semaine ; pour les gros dépôts, restic check --read-data-subset=5% échantillonne les données sans tout lire. Alertez sur un code de sortie non nul.

Aucun des deux ne remplace une vraie restauration de test. Une fois par trimestre, restaurez un fichier que vous pouvez vérifier dans un répertoire temporaire. C'est le seul test qui prouve que la sauvegarde fonctionne.

Étape 5 : Ne sonner que quand c'est important

Si chaque avertissement vous appelle, vous finirez par couper le canal, et il ne sonnera plus pour celui qui compte. Utilisez les conditions d'Echobell pour séparer les niveaux sur un même canal :

status == "failed" || status == "stale" || status == "auth-failed"

Envoyez incomplete et warning vers un second canal Sensible au temps ou normal, pour qu'ils s'affichent sur l'écran verrouillé sans sonner. Ajoutez une plage horaire si vous voulez que les échecs en journée restent discrets, à l'aide des variables UTC décrites dans la référence des conditions.

Questions fréquentes

Comment être averti quand une sauvegarde échoue ?

Enveloppez la commande de sauvegarde, lisez son code de sortie et envoyez un webhook pour tout code non nul. Ajoutez un dead man's switch comme Healthchecks.io pour être aussi prévenu des exécutions qui n'ont jamais démarré.

Sur quels codes de sortie de restic faut-il alerter ?

Alertez fortement sur 1, 10, 11 et 12, qui signalent une vraie défaillance. Traitez 3 (snapshot créé mais certains fichiers illisibles) comme un avertissement à examiner, car il peut masquer un problème de permissions.

Comment savoir si une sauvegarde a cessé de s'exécuter en silence ?

Utilisez un heartbeat : le job envoie un ping à un moniteur en cas de succès, et le moniteur alerte quand le ping est en retard. Un hook d'erreur ne peut pas le détecter, car rien ne s'exécute pour lever l'erreur.

Un code de sortie réussi suffit-il pour faire confiance à une sauvegarde ?

Non. Il signifie que l'outil a terminé, pas que les données sont complètes ou restaurables. Vérifiez l'âge des snapshots, lancez des contrôles d'intégrité périodiques et testez régulièrement une restauration.

Puis-je recevoir un appel plutôt qu'un e-mail ?

Oui. Un e-mail passe facilement inaperçu. Un canal d'appel Echobell se comporte comme un appel entrant et traverse le mode Concentration d'iOS : une sauvegarde échouée à 3 h du matin est donc remarquée.

Pour finir

Trois détecteurs couvrent les trois modes de défaillance : un script enveloppe sur les codes de sortie pour les exécutions qui échouent, un contrôle de fraîcheur pour celles qui réussissent sans utilité, et un heartbeat pour celles qui n'ont jamais lieu. Routez-les vers un canal d'appel, gardez les avertissements sur un canal plus discret, et une sauvegarde cassée devient une réparation de cinq minutes plutôt qu'un week-end perdu.

Téléchargez Echobell pour iPhone ou obtenez-le sur Google Play, créez le canal backups, et lancez le script une fois avec un mot de passe volontairement faux pour l'entendre sonner.

Articles connexes