Comment versionner automatiquement un dossier cible sous Linux grâce à un snapshot Btrfs, systématiquement après l’avoir synchronisé avec rsync.

Introduction

Je vous propose ci-dessous une méthode sous Linux, pour synchroniser un dossier source vers un dossier cible en mode miroir, c’est à dire où les fichiers supprimés de la source sont également supprimés de la cible. Le dossier cible sera systématiquement versionné après la sauvegarde (si possible en mode blocs), et non pas à fréquence fixe par un déclenchement cron, afin de ne pas versionner pour rien.

Pour cela, j’utilise rsync en mode –delete, et le snapshot Btrfs.

Configuration coté serveur de sauvegarde

Le serveur de sauvegarde fait tourner en permanence le daemon rsync. Ce daemon utilise les fichiers de configuration suivants : /etc/rsyncd.conf  et /etc/rsyncd.secrets .

Pour la configuration, je vous passe le rsyncd.secrets  ainsi que les lignes de configuraton générales de rsyncd.conf  pour me concentrer sur les ressources rsync, aussi appelées modules rsync.

Ici le module data pointe vers le dossier org de mon disque de sauvegarde formaté en Btrfs et monté dans /data. Le /data/org (données originales) fait écho au /data/snapshot (données snapshotées).

Le module dir-1 pointe vers un répertoire du même nom, classique.

Les modules dir-2 et dir-3 pointent vers le même dossier org car je souhaite mélanger le contenu de ces dossiers sur le serveur de sauvegarde. Mais ces modules lancent des scripts de snapshot qui sont différents, chaque script va snapshoter les dossiers qui vont bien.

Les modules rsync sont indispensables pour affecter un script post-transfert à un répertoire. Je crois me souvenir que le point est interdit dans le nom du script, sous peine de non-exécution.

Dans le cas d’une sauvegarde sur internet, il faudra sécuriser les échanges par le tunnel SSH, tout en conservant les modules rsync. Coté client l’authentification SSH sera demandée juste avant le mot de passe du module rsync.

Voici un exemple de script de snapshot snapshot-dir-1 . J’ai adopté un format à la syslog dans /var/log/scripts.log .

Pour ce script, je choisis de ne pas snapshoter les répertoires dir-[1-3] en entier, mais de spécifier leurs sous-répertoires qui seront snapshotés. Cela implique que les sous-répertoires à snapshoter ne doivent pas être des dossiers comme les autres, mais des subvolumes btrfs. Par exemple, le dossier /data/org/dir-1/subdir1  a été créé ainsi :

 

Configuration coté client de copie

Voici un exemple de script de sauvegarde avec rsync. Il n’a rien de spécial. Je m’autorise ici le --delete car mon système de fichiers cible est versionné par snapshot, ce qui signifie que je pourrai toujours revenir en arrière en cas de suppression ou modification par erreur de mes données.

A chaque fois qu’un module rsync est utilisé, le script de post-transfert va s’exécuter sur le serveur. En surveillant le fichier de log on devrait trouver :

Limitations de la méthode proposée

La méthode proposée souffre d’un inconvénient, c’est que la copie des fichiers entre le client et le serveur de copie ne peut pas être une copy-on-write (CoW). Donc le versioning par défaut est en mode fichiers et non en mode blocs. En effet, dès que rsync détecte une modification dans un fichier, il commence par créer un nouveau fichier temporaire avec un nouvel inode pour le remplir. A ce stade, nous avons reproduit le comportement de rsnapshot sans le dépasser.

Une optimisation importante apparaît, c’est l’option --inplace  de rsync qui permet de conserver l’inode du fichier cible, et donc de laisser comprendre au système CoW que le fichier cible et sa copie snapshotés n’ont que quelques blocs d’écart (au lieu du fichier entier). Ce réflexe m’apparaît comme étant plutôt logique lorsqu’on connaît rsync, et cela semble être confirmé par d’autres sources.

Pour faire mieux, il faut pratiquer une copy-on-write entre la source et la cible, ce qui implique que le versioning doit être sur le même système de fichiers que les données originales. Pour cela, plus besoin d’utiliser rsync mais simplement un snapshot de subvolume Btrfs (cf. ci-dessus), ou encore un simple cp --reflink. A ce jour, seul Btrfs gère les reflinks.

Pour la sauvegarde distante avec rsync on peut donc se poser la question : soit on ne versionne pas, soit on versionne en mode fichiers au prix d’une surconsommation. Pour des dossiers constitués de petits fichiers comme /etc , /usr  ou /var/www , la surconsommation engendrée sera pas tolérable. Les cas de figure les moins favorables au versioning en mode fichiers sont les très gros fichiers comme les images disques : la conservation d’une version coûtera la taille du fichier en entier.

Pourquoi est-ce utile ?

Le snapshot Btrfs ouvre de nombreuses possibilités pour conserver des états antérieurs de répertoires complets, et donc remonter le temps à la recherche du fichier tel qu’il était avant sa dernière modification ou suppression involontaire.

Imaginez un cas de figure où votre ordinateur est infecté par un ransomware qui crypte tous vos fichiers (sur le disque système et tous les partages réseau), et vous demande ensuite une somme d’argent pour les décrypter. Imaginez que vous vous en rendiez compte trop tard, de sorte que vos sauvegardes ont été écrasées par des fichiers corrompus.

Si vous avez préalablement snapshoté vos données, ce ransomware ne pourra plus vous faire du chantage car la restauration des données ne sera qu’une simple formalité. On se rend donc compte que le snapshot, qui n’est pas une sauvegarde, peut également apporter des avantages sécuritaires en permettant de remonter le temps.