Sauvegarder ses données avec Duplicity

tux-161379_1280Je vous épargnerai le couplet sur la nécessité de mettre en œuvre des sauvegardes régulières et je vous propose d’entrer directement dans le vif du sujet.

Toutes mes données sont stockées sur un NAS maison (basé sur la distribution Open Media Vault). L’objectif est dans un premier temps de mettre en œuvre sur un disque externe des sauvegardes régulières. Dans un second temps, pour plus de sécurité, j’aurai souhaité réaliser une sauvegarde complémentaire sur un serveur distant (il faut encore que je regarde les services appropriés). Toutefois, pour cela, un minimum de sécurité s’impose et si une donnée quitte mon environnement elle ne le fera que cryptée.

Toujours dans l’idée de garder sous le coude un petit aide mémoire, j’ai donc décidé d’écrire quelques billets sur le sujet. Ceux-ci aborderont donc les points suivants :

  • installation de duplicity ;
  • mise en place de sauvegardes totales et incrémentales ;
  • tester la validité de la sauvegarde ;
  • tests de restauration complète sur une sauvegarde totale, incrémentale ;
  • tests de restauration d’un fichier particulier ;
  • démarrage et arrêt du disque externe afin que ce dernier ne fonctionne pas à plein temps (le sujet est en partie traité dans ce billet);
  • sauvegarde cryptée sur un emplacement distant (ce point fera l’objet d’un autre billet).

J’ai choisi de ne pas mettre en œuvre une solution de sauvegarde graphique. La première raison est que je n’ai pas d’écran sur mon NAS. Bien qu’il soit toujours possible d’utiliser un serveur X distant, je pars du principe qu’en cas de problème il y a une probabilité non nulle pour que tout termine en ligne de commande !

Installation de duplicity

Le NAS fonctionne H24, c’est donc sur cette machine que sera installée les différents logiciels permettant de sauvegarder mes données. Open Media Vault est une distribution basée sur Debian. L’installation de duplicity se fait donc très simplement avec la commande « apt-get ».

apt-get install duplicity

Périodicité des sauvegardes

Réaliser des sauvegardes régulières permet d’une part de palier les problèmes matériels qui ne manqueront pas d’arriver un jour et d’autre part de s’offrir un minimum de sécurité en cas de fausse manipulation. Je pars sur une durée de rétention de deux mois, cela signifie que je peux revenir en arrière durant cette période

Pour mettre en œuvre ce type de sauvegarde, je mets en place une sauvegarde totale tous les moins et une incrémentale tous les jours. Certes, en cas de problèmes le 29 du mois, les manipulations à réaliser seront nombreuses (restauration de la sauvegarde totale et restauration des 28 sauvegardes journalières). Certains me diront qu’il serait bien plus facile de réaliser une sauvegarde totale par jour. L’intérêt de duplicity est notamment de cacher cette complexité. Ce point n’est donc pas un vrai problème.

Par contre, en cas de problème sur ma sauvegarde totale, je risque de perdre un mois de données. Effectivement, c’est bien le cas, mais la capacité disque à ma disposition ne me permet pas de faire de sauvegardes totales plus régulièrement (le NAS est quand même en RAID 5, cela devrait tout de même limiter les risques en cas de problème matériel).

Dans mon cas, mes données contiennent plus de 300 Go de photos (oui, je sais, passer un peu plus de temps à les trier ne ferait pas de mal…). Le disque externe que je souhaite utiliser a une capacité de 1To, la solution est donc vite trouvée : deux sauvegardes totales sur le disque. Le reste en incrémental. Avant de réaliser la troisième sauvegarde totale, il faut donc effacer la plus ancienne.

Mise en œuvre des sauvegardes

La commande suivante sauvegardera le dossier « home » dans le dossier « /mnt/svg ». Si la dernière sauvegarde totale date de plus d’un moins, alors duplicity réalisera une nouvelle sauvegarde totale. Si ce n’est pas le cas, ce sera une sauvegarde incrémentale.

Dans le cadre d’une sauvegarde « locale » je ne souhaite pas utiliser de cryptage, d’ou l’option « –no-encryption ».

LISTE_SAUVEGARDE="/home"
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity --no-encryption --full-if-older-than 1M $LISTE_SAUVEGARDE file://$BACKUP_DIR

Le « M » désigne ici une période correspondant à un mois. Il est possible de substituer cette information avec les entrées suivantes :

  • s : seconde ;
  • m : minute ;
  • h : heure ;
  • D : jour ;
  • W : semaine ;
  • M : Mois ;
  • Y : année.

Suite à cette commande, le dossier de sauvegarde contient les trois fichiers suivants :

  • duplicity-full.20150714T123914Z.manifest : des informations sur la sauvegarde ;
  • duplicity-full.20150714T123914Z.vol1.difftar.gz : les données ;
  • duplicity-full-signatures.20150714T123914Z.sigtar.gz : la signature de chaque fichier sauvegardés.

En relançant la sauvegarde, on ajoute 3 fichiers supplémentaires correspondant à la période entre la dernière sauvegarde.

Bien entendu, tous ces fichiers sont directement consultable avec l’outil que vous utilisez habituellement pour gérer vos archives.

Comme mentionné dans ma politique de sauvegarde, je ne souhaite avoir que deux mois de rétention. Là encore duplicity peut se charger du travail. Il suffit d’utiliser la commande « remove-older-than <time>« .

La commande suivante effacera les sauvegardes ayant plus de 70 jours :

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity --no-encryption --full-if-older-than 1M remove-older-than 70D file://$BACKUP_DIR

Tester la validité de la sauvegarde

Afin d’être sur de pouvoir compter sur la sauvegarde, il est opportun de s’assurer que cette dernière n’est pas corrompue. La commande suivante vérifie les données présentes dans les archives présentes sans « /mnt/svg » avec les données présentes dans « /home ».

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity verify -v4 --no-encryption --compare-data file://$BACKUP_DIR $LISTE_SAUVEGARDE;

La vérification se fait fichier par fichier. La place nécessaire à cette vérification est donc limitée.

Il existe une option « –compare-data » qui permet de vérifier aussi le contenu de chaque fichier.

En lançant la commande ci-dessus après avoir modifier un fichier dans « /home », duplicity me retourne la ligne suivante :

Vérification complète : 4 files compared, 1 difference found.

La sauvegarde n’est donc pas conforme à ce qui à été sauvegardé. En mettant en place ce type de vérification, on part du principe que les données ne sont pas accédées durant la fenêtre de sauvegarde.

Restauration des données

Soit la situation initiale suivante sur mon dossier « home » :

  • fichier1.txt ;
  • fichier2.txt.

On réalise une sauvegarde avec la commande suivante :

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity --no-encryption --full-if-older-than 1M $LISTE_SAUVEGARDE file://$BACKUP_DIR

Lister les données présentes dans une sauvegarde

Pour obtenir la liste des fichiers contenus dans une sauvegarde, lancer la commande suivante :

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity list-current-file --no-encryption file://$BACKUP_DIR

On notera que la commande donne pour un même fichier l’ensemble des versions disponibles dans la sauvegarde (discriminées par la date de sauvegarde).

Comparer le backup avec le dossier source

La commande suivante vous permet d’effectuer uen comparaison avec la souvegarde et son dossier source. Les différences seront ainsi facilement mise en évidence.

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity verify --no-encryption file://$BACKUP_DIR $LISTE_SAUVEGARDE

Restauration complète

Suite à la sauvegarde, on restaure les données dans la foulée. La commande suivante permet de restaurer les fichers présents dans le dossier « /mnt/svg » vers le dossier « /home ».

Dans notre cas, les fichiers sauvegardés existent déjà dans « /home ». Par défaut « duplicity » n’écrase jamais de fichier. Il faut donc ajouter l’option « –force » pour forcer la restauration.

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity restore --force --no-encryption file://$BACKUP_DIR

Il est aussi possible de spécifier la version que l’on souhaite restaurer avec l’option « –time ». Pour cela, il faut passer en paramètre la date relative ou absolue du fichier que l’on souhaite restaurer.

La commande suivante effectuera une restauration afin de retrouver les fichiers présent sur le disque il y a une semaine.

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity restore --force --no-encryption --time 1W file://$BACKUP_DIR

Au passage ce test permet de constater que « duplicity » gère tout seul le fait qu’il faille éventuellement restaurer plusieurs sauvegarde pour arrivé au résultat voulu. Réaliser des sauvegardes incrémentales n’augmente pas la complexité de restauration par rapport à des sauvegarde totales.

Il est aussi possible de ne restaurer qu’un dossier particulier. Pour cela, il faut le spécifier à la suite  du dossier désignant la racine du backup. Le dossier en question correspond à l’un des dossiers lister avec la commande duplicity « list-current-file ».

LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity restore --force --no-encryption file://$BACKUP_DIR/dossier_a_retaurer

Restaurer un fichier particulier

Principe

L’option  » –file-to-restore » permet de spécifier les fichiers à restaurer. Pour cela, il faut donner le nom du fichier à restaurer (nom relatif par rapport à la racine de l’archive) ainsi que le nom sous lequel le fichier doit être restauré.

  • si le fichier existe déjà, ne pas oublier l’option « –force » ;
  • il est possible de spécifier la version du fichier avec l’option « –time ».
LISTE_SAUVEGARDE="/home";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/"
duplicity --no-encryption --force --file-to-restore fichier1.txt file://$BACKUP_DIR $LISTE_SAUVEGARDE destination/fichier1.txt

Le chemin relatif du fichier à restauré peut être obtenu avec la commande « list-current-file ».

Exemple

Concrètement, pour restaurer un fichier, j’enchaîne les commandes suivantes :

  • obtenir la liste des fichiers présents dans ma sauvegarde
    • –archive-dir : me permet de spécifier ou se trouve les informations contenant les meta-données. Cela m’évite de les télécharger;
    • le résultat est envoyé dans un fichier. Cela me permet de l’exploiter plus facilement.
duplicity --no-encryption --archive-dir /mnt/stockage/cache/duplicity list-current-files file://$BACKUP_DIR > /tmp/file-liste.txt
  • la restauration
    • –file-to-restore : spécifie le fichier à restaurer. Le nom et le chemin proviennent de la commande exécutée ci-dessus;
    • /root/restore/fichier.txt : le fichier est restauré dans « /root/restore » afin de conserver celui existant déjà sur le disque.
duplicity --no-encryption --archive-dir /mnt/stockage/cache/duplicity --file-to-restore ".test/files/mon fichier.txt" file://$BACKUP_DIR /root/restore/fichier1.txt

Divers

La restauration des données nécessite la copie d’une volumétrie non négligeable de données dans un cache. Ce dernier est situé par défaut dans le dossier « .cache » de l’utilisateur qui lance la commande.

Afin de se prémunir d’un disque plein, il est possible de spécifier au autre dossier de « cache » via la variable d’environnement « TMPDIR ».

La commande suivante modifie l’emplacement du cache :

export TMPDIR=/mnt/stockage/temp

Gestion du périphérique de stockage USB

Lorsque l’on branche un périphérique USB, udev se charge de créer une entrée dans « /dev ». Toutefois, cette entrée de la forme « /dev/sdx » varie en fonction des périfiériques déjà branché à la machine. Pour palier ce problème, il suffit de modifier les règles « udev » afin d’affecter au périphérique en question toujours la même entrée dans « /dev ». Ce point fait l’objet d’un billet.

Et concrètement, que faut-il faire ?

Je souhaite effectuer une sauvegarde ayant les caractéristiques suivantes :

  • sauvegarde journalière ;
  • sauvegarde totale tous les mois ;
  • durée de rétention de 2 mois ;
  • les données à sauvegarder se trouve dans « /media/6c3b39d4-b1f4-4854-9ca9-0b1e068b8aba/Donnees/ »

Avant d’effectuer ma sauvegarde, il est nécessaire de monter mon périférique USB et de vérifier que ce dernier est bien disponible. Ce dernier sera démonté en fin de sauvegarde.

Pour garder une trace de toutes les actions, je souhaite garder les sorties « duplicity » sous forme de log (1 fichier par jour).

Pour remplir ce cahier des charges j’obtiens le script suivant :

#!/bin/bash
 
LISTE_SAUVEGARDE="/media/6c3b39d4-b1f4-4854-9ca9-0b1e068b8aba/Donnees/";
BACKUP_DIR="/mnt/sauvegardeUSB/duplicity/donnees/"
LOG_DIR="/var/log/duplicity"
LOG_FILE=`date +%Y-%m-%d-donnees-duplicity.log`
LOG=$LOG_DIR/$LOG_FILE
 
# Création du dossier de LOG
mkdir --parent $LOG_DIR
 
# Monte le disque de sauvegarde
umount /mnt/sauvegardeUSB
mount /mnt/sauvegardeUSB
 
if mount | grep sauvegardeUSB; then
    # Création du dossier destination
    mkdir --parent $BACKUP_DIR;
    # Supprime les sauvegarde de plus de 4 mois
    echo "Suppression des anciennes sauvegardes"
    duplicity \
        --force \
        --archive-dir /mnt/stockage/cache/duplicity \
    remove-older-than 4M file://$BACKUP_DIR >> $LOG;
    # Réalisation de la sauvegarde
    echo "Sauvegarde"
    duplicity \
        --no-encryption \
        --full-if-older-than 1M \
        --volsize 4500 \
        --archive-dir /mnt/stockage/cache/duplicity \
        --log-file $LOG \
    $LISTE_SAUVEGARDE file://$BACKUP_DIR;
    # réinitialise les variables d'environnement
    unset LISTE_SAUVEGARDE;
    unset BACKUP_DIR;
    # stop le disque
    umount /mnt/sauvegardeUSB
    sdparm --command=eject /dev/sauvegardeUSB
else
    echo "Le disque de sauvegarde n'est pas présent" >> $LOG;
fi

Il ne reste plus qu’a l’ajouter dans la « cron table » pour une exécution journalière. Afin d’être sur que tous les dossiers soient sauvegardés, il est nécessaire de lancer le script avec l’utilisateur « root ».

sudo crontab -e

Et ajouter la ligne suivante :

30 0 * * * /root/bin/sauvegarde-donnees.sh

Améliorations

Voici une liste d’améliorations qui je mettrait en place la journée que j’aurai un peu de temps :

  • envoie de mails en cas de problèmes ;
  • ne pas sauvegarder certains dossiers ou type de fichiers ;
  • mise en place d’une rotation de log.

Références

4 Comments

  1. Hello,

    sauvegarder-donnees-duplycity/ –> sauvegarder-donnees-duplicity/
    périférique, périfiériques –> périphériques

    Tes lignes unset sont réellement nécessaires ? Je n’ai quasiment jamais vu ces lignes dans des scripts et pourquoi ne pas le faire sur toutes les variables alors (LOG, LOG_DIR, LOG_FILE) ?

    Tcho !

    1. Techniquement, les « unset » ne modifient pas le fonctionnement du script. L’idée était de rendre le système après le passage du script dans un état similaire à celui ou il était.
      Par contre, je pense que tu as raison, un peu de cohérence ne ferait pas de mal. Je rajoute donc les « unset » pour les autres variables.

  2. Je me suis mal exprimé désolé, tu as testé de voir si une fois le script terminé tu voyais toujours les variables sur ton système ? Je viens de faire un test car tu m’as mis le doute mais non les variables ne « sortent pas » du script et n’apparaissent pas sur le système.

Laisser un commentaire

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