Script de sauvegarde rsync

Présentation d´un script shell personnel permettant de mettre en place une sauvegarde de données grâce au fameux outil rsync, via Internet, sur un schéma de snapshots. Autrement dit, d’images des données à un instant précis. Le script permet la rotation des sauvegardes et une distribution non linéaire des plus anciennes.

Le contexte

Pour stocker mes précieuses données numériques personnelles j’utilise un NAS, basé sur FreeNAS, dont on a vu tout le processus de configuration dans les deux pages dédiées ici et . Pour sauvegarder ces mêmes données dans un lieu physiquement séparé j’utilise un second NAS situé 500km plus loin. Entre les deux il y a … des lignes téléphoniques de particuliers, toutes simples, avec les limitations d’upload que cela implique : soit à peut près 100ko/s maximum.

Le système d’exploitation est FreeNAS, dérivé de FreeBSD, ce script est donc un script bash, il devrait tourner sans problème à priori sur tout système Unix, Linux et dérivés.

Le principe « snapshots-like », l’utilisation de liens en durs (on va en reparler), et la suppression partielle des anciennes sauvegardes sont inspirés des scripts et informations de François Scheurer, Mike Rubel et Michael Jakl.

Philosophie du script

Tous les possesseurs de Mac connaissent Time Machine, cet utilitaire de sauvegarde extrêmement bien conçu et à ma connaissance malheureusement sans équivalent sous Windows. Et bien en gros ce script de sauvegarde fonctionne de façon similaire, la jolie interface graphique en moins.

Le script crée quotidiennement une image des données sources sur la machine de destination, ainsi on a sur le NAS de sauvegarde un dossier par jour qui contient l´image complète de la source. Pour restaurer un fichier ou un dossier il suffit de choisir la date voulue et on retrouve toute l’arborescence telle qu’elle était à ce moment là. Les sauvegardes sont numérotées : 000 pour la plus récente puis 001 pour celle de la veille, 002 pour l’avant veille, etc…il y a donc une rotation quotidienne des plus anciennes en ajoutant 1 à tous les numéros de dossier. Le script maintient également un dossier « courante » qui est en fait un lien symbolique vers le dossier de la dernière sauvegarde valide.

Listage des sauvegardes distantesAprès un certain temps, avoir une sauvegarde par jour ne sert plus à grand chose, l’idée est donc de supprimer quelques une des plus anciennes sauvegardes en partant du principe que plus elle sont anciennes et moins on a de chance d’en avoir besoin. Donc plus ça va et plus on les espace : une tous les 10 jours, puis 30 jours, etc…

Le fonctionnement en détail

Structure générale

Je vous ai dit que l’on faisait une image des données sources par jour, alors évidemment on ne va pas transférer l’ensemble des données tous les jours. Rsync dispose d’une option magique (–link-dest= »reference ») qui compare les fichiers du dossier source avec le dossier « reference », si l’un est manquant il l’envoi dans la destination mais si le fichier existe dans la référence alors il créé simplement un lien en dur dans la destination vers celui ci. Ainsi pas de transfert de tout ce qui existe déjà !

Sauf que, problème ! Si un utilisateur renomme son dossier « Images » en « Photos », rsync ne le reconnaît pas dans le dossier de reference et on aura peut être 100, 300, 500Go ou plus à renvoyer vers la destination… à 100ko/s je vous laisse faire le calcul. :(Pour éviter ce problème de fichiers ou dossiers renommés, lié à la distance entre les NAS il existe un petit patch qui ajoute à rsync l’option –detect-renamed. –detect-renamed permet donc de repérer et d’éviter cela en utilisant simplement les données déjà à destination pour faire l’image du jour. Du coup je n’utilise pas l’option –link-dest.

Comme finalement on n’utilisera pas l’option link-dest, afin d’avoir les liens en durs vers les fichiers préexistant on va donc commencer par faire une copie complète avec des liens puis on mettra celle-ci à jour. Pour fonctionner correctement en cas de renommage de dossier ou de déplacement de fichier dans la source vers un nouveau dossier, detect-renamed doit avoir dans la destination l’arborescence identique à la source.

Si j’ajoute un contrôle d’unicité au lancement afin de ne pas se retrouver avec 2 scripts qui font la même chose en parallèle, ce qui collerai un gros bazar, ainsi qu’un retour d’erreur par mail à a fin, on obtient en gros cette structure :

A cela s’ajoute la contrainte du débit en upload limité, du coup en cas de gros volume à transférer il se pourrait qu’au bout de 24h la sauvegarde de la veille ne soit pas terminée. Pour traiter ce cas on ajoute un suffixe _incomplete au nom de dossier et on utilise cette sauvegarde comme nouvelle référence pour la suivante, ainsi le travail effectué n’est pas perdu. Le suffixe permettra à la fonction de suppression de ne pas garder la sauvegarde longtemps car elle n’a pas d’interêt.

De plus comme l’upload est limité et toujours en cas de gros volume il peut être contraignant de saturer la ligne téléphone avec la sauvegarde. J’utilise donc un autre patch de rsync : –stop-at. Il permet d’indiquer à rsync de se fermer à une heure prévue. Ainsi de minuit à 8h j’upload presque sans limitation, à 8h rsync se ferme, le script le détecte et relance une instance de rsync avec un débit limité à 50% environ jusqu’à 23h50.

Contrôle de l’unicité

Au lancement, le script créé un fichier « flag » qui sert à enregistrer les différents retours texte en cas de succès ou d’échec. A la fin, ce fichier est copié dans les logs puis supprimé. Le script teste donc si un fichier flag est déjà présent, trahissant ainsi soit une autre instance de script, soit un plantage ou arrêt système ayant empêché le script précédent de se terminer correctement. Dans le premier cas on ferme le rsync précédent, dans le second on supprime la sauvegarde précédente partiellement échouée et on reprend sur des bases saines.

Ceci est géré par cette partie du script :

 

Transfert des fichiers, analyse du code retour

Pour s’assurer du bon déroulement des étapes critiques de la sauvegarde, à chaque exécution de rsync le code de retour est analysé. Parmis les codes remarquables citons :

  • 0 : code signalant que rsync s’est terminé normalement
  • 30 : signalant un arrêt sur timeout => peut être généré par l’option –stop-at, donc on s’en servira pour traiter le cas de l’arrêt programmé à heure fixée
  • 19 : signale un arrêt suite à reception du signal SIGUSER1. C’est ce signal que l’on envoi avec la commande pkill (voir l’extrait de code ci-dessus) si l’instance précédente n’est pas fermée. Le script précédent peut ainsi savoir qu’un nouveau est lancé.

Mise en place et paramétrage du script

Script complet

Voici le script au complet, j’ai essayé de largement commenter le tout, cela sera bien plus lisible en le collant dans un éditeur comme Notepad++ ou autre.

NOTE : Mise à jour du script le 14 octobre 2014 avec une correction d’un bug au niveau du dossier des transferts partiels

 

Le script est prévu pour être exécuté via une tâche cron une seule fois par jour et ce sur la machine hébergeant les sauvegardes, cela me semblais plus robuste pour la création des liens, la rotation et suppression des sauvegarde en cas de coupure internet entre les machines.

Ici il est sur un pool dédié contenant 2 dossiers : Scripts et Sauvegardes. Script héberge le script et les logs, Sauvegardes, l’ensemble des sauvegardes. Bien sûr vous pouvez modifier tout cela dans les paramètres.

Version patchée de rsync

ATTENTION : le script en l’état utilise 2 options de rsync qui n’existent pas dans la version « officielle » actuelle. Il s´agit de –detect-renamed et de –stop-at dont on a parlé précédemment.

Pour inclure ces patches il est nécessaire de compiler rsync vous même en les incluant. Pour cela les sources se situent sur https://rsync.samba.org/ftp/rsync/ dans le dossier /src. Ou plus simplement dans les ports FreeBSD.

Pour ceux qui utilisent FreeNAS en version 64 bits, vous pouvez télécharger ma version ici même.

 Paramétrage du script

L’ensemble des paramètres réglable est situé en tête du script (lignes surlignées en jaune ci-dessus) et sont normalement décrit. L’heure de fin est à mettre avant l’heure de début de la sauvegarde suivante (lancée par cron) pour un fonctionnement plus propre.

Ensuite évidemment il faut régler l’IP du serveur source, le nom d’utilisateur, le port et votre mail. Pour que tout fonctionne bien il faut avoir préalablement paramétré une authentification ssh par clé depuis le serveur distant hébergeant le script vers votre serveur local abritant les fichiers à sauvegarder. La connexion ssh doit avoir été ouverte au moins une fois pour ajouter la « key fingerprint » à la liste des serveurs connus.

La liste des exclus est un fichier contenant une liste des dossiers et des fichiers à ne pas envoyer vers la sauvegarde distante. Il suffit de faire précéder le nom des dossiers ou fichier par – pour les exclure comme sur cet exemple :

#
# Liste des dossiers / fichiers à exclure de la sauvegarde distante

# Exclusion des dossiers
– Jail
– Plugins
– Medias
– Scripts
– Sauvegarde_MID/T??l??chargements
– Sauvegarde_MID/zip et exe*
– Sauvegarde_AD/T??l??chargements
– Sauvegarde_MD

# Exclusion des fichiers et dossiers commençant par un point
#tels que .ssh et autres
– .*

ATTENTION : là encore un piège, il est indispensable d’avoir des sauts de ligne codés au format UNIX. Dans Notepad++ cela se fait avec Edition->Convertir les sauts de lignes.

Et voilà ! Normalement si tout ce passe bien vous allez recevoir un rapport quotidien (à condition d’avoir activé l’option). Celui ci contient les stats rsync du dry-run, s’exécutant donc AVANT l’envoi réel des fichier. Par conséquent quand on y lit « transfered file » il ne s’agit en fait pas des fichiers réellement transféré mais qu’il VA transférer. Si tout se termine en moins de 24h, c’est pareil, mais si vous avez trop de données à envoyer et que cela prend plus de 24h cela correspondra donc à ce qu’il reste à envoyer. Vous voyez la subtilité ?

N’hésitez pas à faire part de vos remarques ou suggestions, je suis preneur de tout ce qui peut l’améliorer car il n’est certainement pas parfait.

 


Vous avez aimé ? N'hésitez pas à partager :
Facebook Twitter Google+ Mail

5 réflexions sur « Script de sauvegarde rsync »

  1. Bonjour,

    Je trouve votre script super bien, par contre j’ai une difficulté, je ne sais pas comment on fait pour compiler rsync avec les options –detect-renamed et de –stop-at

    Est ce que vous auriez un tuto ?

    Pour infos je suis sur ubuntu.

    Merci d’avance pour votre aide

    1. Bonjour Olivier,

      Merci pour le compliment. J’en ai profité pour mettre en ligne une petite mise à jour du script, pas grand chose mais j’avais apporté des modifs alors autant les partager.

      Pour compiler sur Ubuntu c’est très simple : télécharge le code source de rsync (prend la dernière version tant qu’à faire !) et des patches associés à la version ici : https://rsync.samba.org/ftp/rsync/src/. Ce sont les fichiers .tar.gz
      Ensuite tu les décompresses où tu veux pour avoir un dossier rsync-3.1.1 contenant les sources et également le dossier « patches » avec… les patches !

      En ligne de commande, tu te met dans le dossier rsync et tu exécutes dans l’ordre:

      patch -p1 < patches/time-limit.diff patch -p1 < patches/detect-renammed.diff ./configure make

      Et voilà ! tu retrouves dans le dossier des sources l'exécutable "rsync" et si tu lances "./rsync --help" tu verras les nouvelles options dans la liste.

      Pour finir tu peux remplacer les rsync d'origine dans /usr/bin/rync par cette version patchée comme ça c'est cette version qui s’exécutera en tapant simplement rsync

      1. Bonjour Mickaël,

        Merci beaucoup pour ta réponse et pour ton partage, je vais essayer ce week-end les infos que tu me donnes.

        Pour infos j’utilise déjà le rsync pour sauvegarder les données de mon entreprise sur un serveur externe du mais ton code me semble tellement génial que j’ai hâte de le mettre en place.

        Au passage encore félicitation pour ton travail, étant également codeur en PHP si je peux un jour t’apporter mon aide ce serait avec un très grand plaisir.

        Cordialement,

      2. Bonjour
        Je suis nouveau sur Linux et je suis intéressé par votre script de sauvegarde.
        Je suis sur Ubuntu 16.04.2LTS.
        Or, j’ai lancé la procédure de compilation de rsync-3.1.2 avec les 2 patches. L’adjonction des 2 patches se passe bien, au détail près qu’il faut faire SUDO et qu’il y a une faute sur la 2ème commande « patch » : renamed ALD renammed.
        Par contre, pour la dernière étape « ./configure make », impossible d’y parvenir…
        Voici le message d’erreur obtenu :
        nicolas@bureau:~/rsync-3.1.2$ sudo ./configure make
        configure.sh: WARNING: you should use –build, –host, –target
        configure.sh: Configuring rsync 3.1.2
        checking build system type… Invalid configuration `make’: machine `make’ not recognized
        configure.sh: error: /bin/bash ./config.sub make failed
        nicolas@bureau:~/rsync-3.1.2$ ./rsync –help
        bash: ./rsync: Aucun fichier ou dossier de ce type

        Pouvez-vous m’aider à ce stade car l’esprit de votre script correspond exactement à ce que je recherche aujourd’hui ?
        Merci d’avance,
        Nicolas

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *