27
janvier 2012

Gestion des sauvegardes avec rsync

Afin d'optimiser le temps et le volumes de mes sauvegardes j'ai réfléchi à différentes solutions. Jusqu'à présent j'utilisais rsync via un petit script maison et puis j'ai fais des recherches sur rdiff-backup pensant que celui-ci transférait uniquement les blocs de fichier modifié alors que rsync transférait tout la totalité du fichier modifié. Grosse erreur, tout deux transfert uniquement les blocs de fichiers modifier. Donc comment optimiser un petit peu tout ça ?

Grâce au journaux de linuxfr j'ai découvert l'option --link-dest de rsync.

Mise à jour :
- 15/04/2012 : possibilité d'avoir plusieurs sources de sauvegardes.
- 02/04/2012 : mise à jour de la gestion des dates.
- 27/03/2012 : gestion de la sauvegarde sur ftp d'ovh ou HubiC.

L'idée de départ est d'avoir une gestion de version de backup sur x jours, c'est ce qu'on appel la rétention. Le problème dans ce cas va être le volume de données à gérer. Pour contourner ce problème Linux dispose des "liens en dur" (hard link). Pas forcement créé pour au début mais vachement pratique quand même.
Imaginons :

  • le répertoire /home/flipflip comme répertoire à sauvegarder
  • le répertoire /mnt/backup comme répertoire de stockage des sauvegardes

#!/bin/bash
# +--------------------------------
# | Définition des répertoires
# +--------------------------------
BASETARGET="/media/backup"
TARGET="${BASETARGET}/sauvegarde"

# Tableau des répertoires à sauvegarder
SOURCE[0]="/home/USERS/Images"
SOURCE[1]="/home/USERS/Modèles"

# +--------------------------------
# | mode de montage de target
# | valeur possible : ftp, dav
# +--------------------------------
MODE="dav"

# +--------------------------------
# | url du partage webdav 
# | voir : http://www.blogoflip.fr/?ovh-hubic-en-ligne-de-commande
# +--------------------------------
URLDAV="https://cloudnas1.ovh.com/6z9affd86ee8486468b17be15938b82a/"

# +--------------------------------
# | Information méthode ftp
# | voir : http://www.blogoflip.fr/?sauvegarde-sur-le-ftp-d-ovh
# +--------------------------------
USERFTP=
PASSFTP=
HOTEFTP=

RETENTION=5

# Les répertoires de sauvegardes ont pour structure YYYY-MM-DD
OLDDATE=`date +%Y-%m-%d --date '1 day ago'`
DAYDATE=`date +%Y-%m-%d`

remove_old() {
	# Gère la rétention des backups
	LS=`ls -d ${TARGET}/2* | sort | head --lines=-${RETENTION} | xargs rm -rf`
	if [ ${?} -ne 0 ]
	then
		echo "Une erreur c'est produite pendant la rotation des backup"
		exit 1
	fi
}

go_backup() {	
	# La partie intéressante est --link-dest
	# Ce paramêtre créé automatiquement des liens hard si le fichier est identique entre OLD et JOUR
	for BACKUP in "${SOURCE[@]}"
	do
		rsync -ah --progress --delete-after --stats --no-owner --no-group --safe-links --link-dest=${TARGET}/${OLDDATE} ${BACKUP} ${TARGET}/${DAYDATE}/
	done
}

mount_dav() {
	if [ ! -d $HOME/.davfs/secrets ]
	then
		mount -t davfs $URLDAV $BASETARGET
		if [ $? -ne 0 ]
		then
			echo "Erreur pendant le montage"
			exit 1
		fi
	else
		echo "Le fichier $HOME/.davfs/secret n'existe pas"
		echo "Créer le fichier secrets contenant :"
		echo "http://URLWEBDAV login password"
		exit 1
	fi
}

mount_ftp () {
	curlftpfs#$USERFTP:$PASSFTP@$HOTEFTP $BASETARGET
	if [ $? -ne 0 ]
	then
		echo "Une erreur c'est produite pendant le montage"
		exit 1
	fi
	
}

umount_backup () {
        umount $BASETARGET
        if [ $? -ne 0 ]
        then
                echo "Erreur pendant le demontage de $BASETARGET"
                exit 1
        fi
}

case $MODE in
	dav) mount_dav ;;
	ftp) mount_ftp ;;
	*) echo "Erreur de paramétrage du mode" ;;
esac

if [ -d ${TARGET}/${DAYDATE} ]
then
	echo "Le répertoire ${DAYDATE} existe déjà"
	go_backup
else
	go_backup
	remove_old
fi

umount_backup
exit 0

  • TARGET est le répertoire de stockage des sauvegardes;
  • SOURCE est le répertoire à sauvegarde.

JOUR, MOIS, ANNEE vont nous permettre de créer une structure de répertoires sous la forme YYYY-MM-DD. RETENTION correspond au nombre de jours de sauvegarde à conserver en plus du jour de lancement de la sauvegarde.

Le script est découpé en deux fonctions :

  • remove_old qui supprime les anciennes sauvegardes;
  • go_backup qui lance la sauvegarde.

Ensuite une condition toute bête qui test si le répertoire du jour de la sauvegarde existe dans ce cas il lance uniquement la sauvegarde sinon il lance la rotation des sauvegardes et la sauvegarde. Cette condition empêche la suppression des anciennes sauvegardes dans le cas ou vous lancez plusieurs fois par jour la sauvegarde.

Mise en situation

Je suis le 20 du mois, je lance pour la première fois la sauvegarde, mon répertoire SOURCE contient :

drwx------ 2 flipflip flipflip 4096  2 nov.   2010 dir1
-rwx------ 1 flipflip flipflip    0 20 janv. 12:10 fic
-rwx------ 1 flipflip flipflip    0  2 nov.   2010 fic1
-rwx------ 1 flipflip flipflip    0  2 nov.   2010 fic2

Et pour le moment TARGET est vide, je lance la sauvegarde :

ls: impossible d'accéder à /mnt/backup/2*: Aucun fichier ou dossier de ce type
--link-dest arg does not exist: /mnt/backup/2012-01-19
cd+++++++++ ./
>f+++++++++ fic
>f+++++++++ fic1
>f+++++++++ fic2
cd+++++++++ dir1/
>f+++++++++ dir1/ficdir1
>f+++++++++ dir1/ficdir2

Number of files: 7
Number of files transferred: 5
Total file size: 0 bytes
Total transferred file size: 0 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 132
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 340
Total bytes received: 113

sent 340 bytes  received 113 bytes  906.00 bytes/sec
total size is 0  speedup is 0.00

Les deux premiers messages sont normaux puisque c'est la première fois qu'on le lance, le répertoire TARGET contient maintenant :

drwx------ 3 flipflip flipflip 4096 20 janv. 12:10 2012-01-20

Et un ls -l dans 2012-01-20 donne :

drwx------ 2 flipflip flipflip 4096  2 nov.   2010 dir1
-rwx------ 1 flipflip flipflip    0 20 janv. 12:10 fic
-rwx------ 1 flipflip flipflip    0  2 nov.   2010 fic1
-rwx------ 1 flipflip flipflip    0  2 nov.   2010 fic2

Jusque la tout va bien. Le lendemain arrive donc nous somme le 21, je travaille sur le fichier fic, il est l'heure de partir je lance la sauvegarde :

cd..t...... ./
>f.st...... fic

Number of files: 7
Number of files transferred: 1
Total file size: 7 bytes
Total transferred file size: 7 bytes
Literal data: 7 bytes
Matched data: 0 bytes
File list size: 132
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 193
Total bytes received: 35

sent 193 bytes  received 35 bytes  456.00 bytes/sec
total size is 7  speedup is 0.03

Seul le fichier fic à été transféré, maintenant le répertoire TARGET contient :

drwx------ 3 flipflip flipflip 4096 20 janv. 12:10 2012-01-20
drwx------ 3 flipflip flipflip 4096 21 janv. 12:15 2012-01-21

ls -l 2012-01-20
drwx------ 2 flipflip flipflip 4096  2 nov.   2010 dir1
-rwx------ 1 flipflip flipflip    0 20 janv. 12:10 fic
-rwx------ 2 flipflip flipflip    0  2 nov.   2010 fic1
-rwx------ 2 flipflip flipflip    0  2 nov.   2010 fic2

ls -l 2012-01-21
drwx------ 2 flipflip flipflip 4096  2 nov.   2010 dir1
-rwx------ 1 flipflip flipflip    7 21 janv. 12:15 fic
-rwx------ 2 flipflip flipflip    0  2 nov.   2010 fic1
-rwx------ 2 flipflip flipflip    0  2 nov.   2010 fic2

dir1, fic1 et fic2 sont des hard link qui occupe bien moins de place que le fichier d'origine. Il y a uniquement fic qui est mis à jour. La semaine continue et nous sommes le 26 normalement le répertoire TARGET devrait ressembler à ça :

drwx------ 3 flipflip flipflip 4096 27 janv. 12:10 2012-01-20
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-21
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-22
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-23
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-24
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-25

J'ai programmé une rétention de 5 jours, je lance la sauvegarde et magie :

drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-21
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-22
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-23
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-24
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-25
drwx------ 3 flipflip flipflip 4096 27 janv. 12:15 2012-01-26

La journée du 20 a disparue.

Je vous laisse bricoler les options de rsync.

Administrateur système de métier mais surtout curieux de découvrir de nouvelles technos très orientées DIY. A mes heures perdues je fais de la photo avec toujours une petite envie d'intégrer des DIY sous forme de timelaps à base de raspberry.

6 commentaires

flipflip a dit

@Seb : Effectivement ça peut pas marcher pour ftp, d'un autre côté j'ai eu énormément de problème avec curlftp qui n'est plus dev. J'ai laissé tombé au profit d'un montage webdav ou sshfs (pas prévue dans la version en ligne du script). Disons que le programme a évolué et maintenant le montage doit être géré par l'admin et non par le programme du coups ça laisse bien plus de liberté et le programme se limite à transférer les données... Si j'arrive à trouver un moment je publierais la nouvelle version.

Répondre

Seb a dit

--link-dest ne peut pas marcher via FTP, tout simplement parce que les hard-links (tout comme les symbolic) n'existent pas avec ce protocole.

Il suffit de monter le dossier avec curlftpfs et d'essayer d'en créer un pour remarquer que ça ne fonctionne pas.

Le script va donc recopier à chaque fois l'intégralité du contenu.

Répondre

flipflip a dit

@Max : Ce n'est pas des liens symbolic mais des hardlinks.

Répondre

Max a dit

Comment est-ce que ça peut marcher.
Web dav ne support pas la création de lien symbolic, donc je suppose que davfs2 non plus et pourtant rsync avec --link-dest le ferait ???

Répondre

flipflip a dit

@Rondodu : Salut, xargs est bien pratique après je n'ai pas trop vérifié si il est dispo sur toute les distributions.

J'ai fais une petite mise à jour du script en remplacant OLD=`expr[...] par OLD=`date +%d --date '1 days ago'`, c'est ce que j'utilise dans mon gestionnaire de backup que j'écris au boulot et qui devrait être publié courant mars sur mon blog.

Je suis pas certain d'avoir compris ton coups de tail, le but du ls est d'obtenir la liste des répertoires qui peuvent être supprimés donc qui ont dépassés la durée de rétention.

ls -d 2* : tout les répertoires commençant par 2
sort : trie les répertoires du plus ancien au plus récent
head --lines=-X : affiche les X premiers résultat de sort
xargs : supprime le résultat de tout ce qui le précède.

Répondre

Rondodu a dit

Bonjour,

Je me résignais doucement à faire des backup avec des noms sympa comme « hourly.1 » et « daily.3 », mais je suis inspiré par l’idée du ls | sort | head | xargs — je ne pense jamais à xargs. Je vais voir si je peux en faire quelque chose.

Par contre, et sans avoir testé, il me semble que ton calcul du jour de la veille est plutôt bancal. La veille du 1er mars 2012 est le 0 mars 2012, si je ne m’abuse. Du coup, en début de mois, deux fois trop de données pendant 5 jours. En partant de ton idée précédente, pour ne pas faire un ls | sort | tail ? D’autant qu’avec la méthode actuelle, un jour de backup loin de ton disque de sauvegarde et tu repars de zéro.

Répondre

Écrire un commentaire

Quelle est la première lettre du mot gapw ? :

Gestion des sauvegardes avec rsync - Philippe Maladjian - Péripéties bucoliques d'un administrateur systèmes au royaume de la virtualisation, du stockage et accessoirement photographe à ses heures perdues