Programmer une sauvegarde incrémentale régulière

Mine de rien le cumul des données partagées présentes sur mon serveur Dell PowerEdge T310 approche des 3 To, elles ont beau être installées sur un volume RAID 5, je reste inquiet aux conséquences de la perte de décennies de numérisation de mes données personnelles. Aussi je me suis penché sur un système annexe de sauvegarde incrémentale. L’idée est de faire une copie complète des données une fois, puis régulièrement une copie des seuls fichiers qui ont été modifiés, rajoutés et de supprimer les fichiers de la sauvegarde qui ont disparu des données d’origine. Pour cela j’ai acheté un disque externe de 4To USB qui est connecté par USB à mon serveur Dell.

Le but de la manœuvre est de sauvegarder tous les jours de manière incrémentale les données de /home et de mon répertoire /data à l’exclusion de certains fichiers et répertoires Je me suis largement inspiré du script qu’on peut trouver par ici que j’ai adapté à mes besoins.

Voici le code commenté du script sauvegarde (droit d’exécution 755) que j’ai placé sous /usr/local/sbin en question :

#!/bin/bash
# Script sauvegarde rsync https://www.funix.org inspiré par
# celui de  Mickaël BONNARD ( https://www.mickaelbonnard.fr )
# sous licence MIT ( http://choosealicense.com/licenses/mit/ )

# Variables
# date et heure
jour=`date +%d-%B-%Y`
# répertoire contenant les logs
log="/var/log/sauvegarde"

# répertoires à sauvegarder
local1="/data"
local2="/home"

# point de montage du disque de sauvegarde
distant="/media/sauvegardes"

# fichiers et répertoires à exclure de la sauvegarder
excludes1="/root/bin/exclude-data.txt"
excludes2="/root/bin/exclude-home.txt"

# test de vérification de la présence du disque de sauvegarde
if [ ! -e "$distant" ]
then
    echo "Le disque de sauvegarde n'est pas monté, arrêt du script"
    exit
fi

echo "-------------------------------------------------------------" > $log/sauvegarde_$jour.log

# nom de la sauvegarde dans le journal
echo "Sauvegarde de $local1 et $local2 du $(date +%d-%B-%Y)" >> $log/sauvegarde_$jour.log

echo "-------------------------------------------------------------" >> $log/sauvegarde_$jour.log

# heure de début du transfert dans le journal
echo "Heure de demarrage de la sauvegarde : $(date +%H:%M:%S)" >> $log/sauvegarde_$jour.log

echo "-------------------------------------------------------------" >> $log/sauvegarde_$jour.log

# transfert des fichiers

rsync -az --stats --delete-after --exclude-from=$excludes1 $local1 $distant >> $log/sauvegarde_$jour.log
rsync -az --stats --delete-after --exclude-from=$excludes2 $local2 $distant >> $log/sauvegarde_$jour.log

# -a : mode archivage ( équivalent -rlptgoD ).
# -z : compression des données pendant le transfert.
# -- stats donne des informations sur le transfert (nombre de fichiers…).
# --delete-after : supprime les fichiers qui n’existent plus dans la source après le transfert dans le dossier de destination.

status=$?

echo ""  >> $log/sauvegarde_$jour.log

#code d'erreurs rsync

case $status in
0) echo Succès >> $log/sauvegarde_$jour.log;;
1) echo Erreur de syntaxe ou d'utilisation >> $log/sauvegarde_$jour.log;;
2) echo Incompatibilité de protocole >> $log/sauvegarde_$jour.log;;
3) echo Erreurs lors de la sélection des fichiers et des répertoires d'entrée/sortie >> $log/sauvegarde_$jour.log;;
4) echo Action non supportée : une tentative de manipulation de fichiers 64-bits sur une plate-forme qui ne les supporte pas \
 ; ou une option qui est supportée par le client mais pas par le serveur. >> $log/sauvegarde_$jour.log;;
5) echo Erreur lors du démarrage du protocole client-serveur >> $log/sauvegarde_$jour.log;;
6) echo Démon incapable d'écrire dans le fichier de log >> $log/sauvegarde_$jour.log;;
10) echo Erreur dans la socket E/S >> $log/sauvegarde_$jour.log;;
11) echo Erreur d'E/S fichier >> $log/sauvegarde_$jour.log;;
12) echo Erreur dans le flux de donnée du protocole rsync >> $log/sauvegarde_$jour.log;;
13) echo Erreur avec les diagnostics du programme >> $log/sauvegarde_$jour.log;;
14) echo Erreur dans le code IPC>> $log/sauvegarde_$jour.log;;
20) echo SIGUSR1 ou SIGINT reçu >> $log/sauvegarde_$jour.log;;
21) echo "Une erreur retournée par waitpid()" >> $log/sauvegarde_$jour.log;;
22) echo  Erreur lors de l'allocation des tampons de mémoire principaux >> $log/sauvegarde_$jour.log;;
23) echo Transfert partiel du à une erreur >> $log/sauvegarde_$jour.log;;
24) echo Transfert partiel du à la disparition d'un fichier source >> $log/sauvegarde_$jour.log;;
25) echo La limite --max-delete a été atteinte >> $log/sauvegarde_$jour.log;;
30) echo Dépassement du temps d'attente maximal lors d'envoi/réception de données >> $log/sauvegarde_$jour.log;;
35) echo Temps d’attente dépassé en attendant une connection >> $log/sauvegarde_$jour.log;;
255) echo Erreur inexpliquée >> $log/sauvegarde_$jour.log;;
esac

echo "-------------------------------------------------------------" >> $log/sauvegarde_$jour.log

# heure de fin dans le journal

echo "Jour de fin de sauvegarde : $(date +%d-%B-%Y)" >> $log/sauvegarde_$jour.log
echo "Heure de fin de la sauvegarde : $(date +%H:%M:%S)" >> $log/sauvegarde_$jour.log

echo "-------------------------------------------------------------" >> $log/sauvegarde_$jour.log

exit

On lancera manuellement la première fois le script pour faire la copie complète initiale. Pour mes presque 3 To de données, ça a pris 30 heures ! Voilà la trace de la commande :

Le fichier d’exclusion ressemblera à ça, exemple avec le fichier exclude-home.txt

- /home/benjamin
- /home/benjamin/**
- /home/clamav
- /home/clamav/**
- /home/lost+found
- /home/lost+found/**
- /home/openvas
- /home/openvas/**

- /home/*/.gconf
- /home/*/.gconfd
- /home/*/.dbus
- /home/*/.gnome2
- /home/*/.qt
- /home/*/.thumbnails
- /home/*/.gvfs
- /home/*/.cache
- /home/*/tmp
- /home/*/Téléchargements

On lancera manuellement la première fois le script pour faire la copie complète initiale. Pour mes presque 3 To de données, ça a pris 30 heures ! Voilà la trace de la commande :

-------------------------------------------------------------
Sauvegarde de  du 19-mai-2019
-------------------------------------------------------------
Heure de demarrage de la sauvegarde : 10:52:00
-------------------------------------------------------------

Number of files: 173,245 (reg: 164,016, dir: 7,932, link: 1,297)
Number of created files: 173,245 (reg: 164,016, dir: 7,932, link: 1,297)
Number of deleted files: 0
Number of regular files transferred: 164,016
Total file size: 3,206,903,342,348 bytes
Total transferred file size: 3,206,903,246,843 bytes
Literal data: 3,206,903,246,843 bytes
Matched data: 0 bytes
File list size: 6,159,933
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 3,162,117,031,591
Total bytes received: 3,178,395

sent 3,162,117,031,591 bytes  received 3,178,395 bytes  16,697,620.39 bytes/sec
total size is 3,206,903,342,348  speedup is 1.01

Number of files: 102,431 (reg: 93,409, dir: 8,992, link: 29, special: 1)
Number of created files: 102,431 (reg: 93,409, dir: 8,992, link: 29, special: 1)
Number of deleted files: 0
Number of regular files transferred: 93,409
Total file size: 76,774,345,955 bytes
Total transferred file size: 76,774,345,296 bytes
Literal data: 76,774,345,304 bytes
Matched data: 0 bytes
File list size: 3,013,885
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 56,725,836,374
Total bytes received: 1,832,039

sent 56,725,836,374 bytes  received 1,832,039 bytes  11,132,895.38 bytes/sec
total size is 76,774,345,955  speedup is 1.35

Succès
-------------------------------------------------------------
Heure de fin de la sauvegarde : 16:53:10
-------------------------------------------------------------

Ensuite pour que la sauvegarde devienne quotidienne, sous /etc/cron.daily j’ai créé le fichier exécutable sauvegarde contenant

#!/bin/bash
/usr/local/sbin/sauvegarde

Les sauvegardes incrémentales avec création/modification et suppression de fichiers sont ensuite, heureusement, bien plus rapides et durent à peine quelques minutes. En voici une trace :

-------------------------------------------------------------
Sauvegarde de  du 24-mai-2019
-------------------------------------------------------------
Heure de demarrage de la sauvegarde : 13:39:04
-------------------------------------------------------------

Number of files: 118,632 (reg: 110,799, dir: 6,536, link: 1,297)
Number of created files: 0
Number of deleted files: 54,618 (reg: 53,221, dir: 1,397)
Number of regular files transferred: 0
Total file size: 2,727,907,903,951 bytes
Total transferred file size: 0 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 3,342,069
File list generation time: 5.537 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 3,357,594
Total bytes received: 11

sent 3,357,594 bytes  received 11 bytes  447,680.67 bytes/sec
total size is 2,727,907,903,951  speedup is 812,456.47

Number of files: 102,427 (reg: 93,405, dir: 8,992, link: 29, special: 1)
Number of created files: 1 (reg: 1)
Number of deleted files: 11 (reg: 11)
Number of regular files transferred: 2
Total file size: 76,774,768,138 bytes
Total transferred file size: 72 bytes
Literal data: 72 bytes
Matched data: 0 bytes
File list size: 3,014,166
File list generation time: 0.737 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 3,043,261
Total bytes received: 69

sent 3,043,261 bytes  received 69 bytes  2,028,886.67 bytes/sec
total size is 76,774,768,138  speedup is 25,227.22

Succès
-------------------------------------------------------------
Heure de fin de la sauvegarde : 13:39:35
-------------------------------------------------------------

Sauvegarder c’est bien, mais quid de la restauration, en fait c’est très simple ! Dans le cas présent les fichiers vont se retrouver (non compressés) dans le répertoire /media/sauvegardes, il est donc très simple de récupérer une copie. C’est donc un inconvénient en terme de stockage de la sauvegarde (puisqu’il faut a minima le même espace de stockage que les répertoires à sauvegarder) mais la restauration en est largement facilitée.

Plus fin encore si vous souhaitez faire une sauvegarde distincte pour chaque jour, chaque semaine (celle du lundi) et du mois (le 1er du mois) pour pouvoir revenir à un état précis d’un jour particulier, je pouvais consulter ce site. Je pense que ça peut être utile pour les développeurs ou pour tous ceux qui ont le besoin de récupérer des fichiers à un instant t de leur vie.

2 réflexions sur « Programmer une sauvegarde incrémentale régulière »

  1. Bonjour.
    Après avoir testé plusieurs scripts et outils de sauvegarde, j’ai découverts Borg Backup qui est lui-même un fork d’Attic. Je le trouve puissant, léger (pas de base de données), rapide et avec de nombreuses possibilités pour peu que l’on maîtrise la ligne de commande (l’aide sur leur site est extrêmement bien faite).
    En plus il compresse et fait de la déduplication (donc gain de place).
    Cela fait quasiment 2 ans que je l’utilise et je n’ai jamais eu à m’en plaindre, que ce soit au niveau sauvegarde ou restauration (eh oui, ça arrive…). J’ai d’ailleurs écrit un article dessus (https://doc.ubuntu-fr.org/borgbackup).
    Je pense qu’il mérite de s’y pencher…

  2. je ne connaissais pas, ça parait effectivement une solution séduisante bien plus puissante que mon petit script bash (qui fait le boulot toutefois mais qu’avec une seule version de sauvegarde).

Laisser un commentaire