Sauvegarde incrémentale de fichiers avec RSYNC et SSH
Voici un script que j'ai écrit il y a quelques années pour un besoin de sauvegarde de fichiers que j'avais à l'époque. Le principe est très simple et la méthode est efficace: utilser l'utilitaire rsync avec ses options extraordinaires pour faire une copie complète ou incrémentielle à travers un tunnel ssh depuis le client vers le serveur de sauvegarde.
En effet, rsync permet grâce à ses nombreuses options de manipuler soigneusement l'opération de copie de fichiers. Il permet, entre autres, de minimiser le volume copié et économiser la bande passante en cas de copie distante puisqu'il utilise un protocole de mise à jour qui ne copie que les nouveautés ou les modifications au lieu de la totalité du fichier. Il permet aussi d'effectuer une synchronisation unidirectionnelle du client vers le serveur de sauvegarde tout en archivant sur ce dernier les anciennes versions qui n'existent plus sur le client.
Le script ci-dessous permet de sauvegarder une liste de fichiers et ou répertoires depuis le client vers le serveur avec le cycle suivant:
- Une sauvegarde complète le jour J (par défaut lundi).
- Une sauvegarde incrémentale du jour J+1 au jour J+6.
- Une sauvegarde complète le jour J+7 (soit une sauvegarde complète par semaine).
Notez qu'il faudra créer un cronjob qui exécute le script quotidiennement. D'autres actions sont à prévoir également, comme la génération de la clé ssh, bien lire les commentaires pour plus de détails, adaptez également les variables à votre cas.
Voila le script à copier quelque part sur le client à sauvegarder.Pour l'instant les commentaires sont en anglais, je les mettrais en français dès que possible.
#!/bin/sh
#############################################################################
# Script to do weekly full backup and daily incremental backup using rsync #
# over SSH #
# Adapted from script by Brian Hone found here: #
# http://linuxfocus.org/English/March2004/article326.shtml #
# Which adapted from script found on the rsync.samba.org #
# #
# Kadimi Mohamed-Amine 08-08-2007 #
# This script is freely distributed under the GPL #
#############################################################################
#
# - By default, the full backup is made monday, you can specify another day
# by entering a number from 1 to 7 (1 is monday, 2 is tuesday ...)
#
#FULL_DAY=1
#
# - BACKUP_ROOT is the parent directory from which you want rsync to start the backup
#
# - BACKUP_LIST is a text file where you specify files/directories you
# want to backup (one per line), the paths on this file must be relative
# to the path set in BACKUP_ROOT
#
# For example, if you want to backup only /home/user1 and /home/user2
#
# You can do it this way :
# BACKUP_ROOT=/home
# and the content of the file specified in BACKUP_LIST is:
# user1
# user2
#
# You can also do it this way :
# BACKUP_ROOT=/
# and the content of the file specified in BACKUP_LIST is:
# home/user1
# home/user2
#
BACKUP_ROOT=/
BACKUP_LIST="/root/backup_list"
#
# excludes file - contains one wildcard pattern per line of files to exclude
# - This is a rsync exclude file. See the rsync man page.
#
EXCLUDES_LIST="/root/backup_exclude"
#
# Hostname or IP adress of the remote backup server
#
BACKUP_SRV=server_hostname
#
# Root directory that stores backups on the remote server
#
ARCHIVE_ROOT=/mnt/backup/
#
# Log file; must be writable by the user who executes this script
#
LOGFILE="/var/log/backup-rsync.log"
#
# Remote user. Used by ssh. This is the user who connects to the remote backup server
# Must have write access on $ARCHIVE_ROOT
#
# - You should generate and share a ssh key to connect securely through ssh
# without providing a password. Procedure to do that is (tested on debian):
# 1- Generate the key (e.g. backup_key) on the local host by running :
# ssh-keygen -f ~/.ssh/backup_key
# backup_key and backup_key.pub are created in ~/.ssh/
#
# 2- Add the generated public key to the file ~/.ssh/authorized_keys on the remote host:
# cat ~/.ssh/backup_key.pub | ssh remoteuser@remotehost "cat - >>.ssh/authorized_keys"
#
# For security reasons, avoid backing up using the remote root account
#
REMOTE_USER=username
#
# mail address for status updates
# - This is used to email you a status report
# - Comment it if you don't want to mail the report
#
MAILADDR=yourmail@yourdomain.com
#
# HOSTNAME
# This is used for creating a directory specific to this host on the remote host
#
HOSTNAME=client_hostname
#########################################
# From here on out, you probably don't #
# want to change anything unless you #
# know what you're doing. #
#########################################
#
# Calculate WEEK_NUM
# - This is the week number of year, it depends on the variable FULL_DAY
# the value of FULL_DAY is considered as the first day of week
#
# - By default the command `date +%W` considers monday as first day of week, so if the day of
# the full backup is different from monday then we must make additional operations
#
#
if [ $FULL_DAY ] && [ $FULL_DAY -le 7 ] && [ `date +%u` -ge $FULL_DAY ] ; then
WEEK_NUM=`expr $(date +%W) + 1`
else
WEEK_NUM=`date +%W`
fi
#
# ARCHIVE_DIR
# This is the directory (full path) of the current week backups (on the remote host)
# The name of directory indicates the number of the week in the year (e.g 2007-32)
#
ARCHIVE_DIR="$ARCHIVE_ROOT/$HOSTNAME/`date +%Y`-$WEEK_NUM"
#
# Directory which holds our current datastore
#
CURRENT=main
#
# Directory which we save incremental changes to (e.g monday_06-08-2007)
#
INCREMENTDIR=`date +%A_%d-%m-%Y`
#
# Options to pass to rsync
# -r for recursivity must be explicite in spite of -a because --files-from (see man rsync)
#
OPTIONS="--force --ignore-errors --delete --delete-excluded \
--exclude-from=$EXCLUDES_LIST --backup --backup-dir=$ARCHIVE_DIR/$INCREMENTDIR \
-arhv --files-from=$BACKUP_LIST"
# our actual rsyncing function
do_rsync()
{
rsync $OPTIONS $BACKUP_ROOT $REMOTE_USER@$BACKUP_SRV:$ARCHIVE_DIR/$CURRENT >> $LOGFILE 2>&1
return
}
# our post rsync accounting function
do_accounting()
{
if [ $1 ] ; then
echo "Backup Accounting for Day $INCREMENTDIR on $HOSTNAME:">/tmp/rsync_script_tmpfile
echo >> /tmp/rsync_script_tmpfile
echo "################################################">>/tmp/rsync_script_tmpfile
ssh $REMOTE_USER@$BACKUP_SRV du -s $ARCHIVE_DIR/* >> /tmp/rsync_script_tmpfile
echo "Mail $1 -s "$HOSTNAME Backup Report" < /tmp/rsync_script_tmpfile"
Mail $1 -s "$HOSTNAME Backup Report" < /tmp/rsync_script_tmpfile
echo "rm /tmp/rsync_script_tmpfile"
rm /tmp/rsync_script_tmpfile
fi
}
# some error handling and/or run our backup and accounting
if [ $BACKUP_LIST ]; then
if [ $EXCLUDES_LIST ]; then
if [ -f $BACKUP_LIST ]; then
if [ -f $EXCLUDES_LIST ] ; then
# make sure our backup tree exists
ssh $REMOTE_USER@$BACKUP_SRV install -d $ARCHIVE_DIR/$CURRENT
echo >> $LOGFILE
echo "=========================================================" >> $LOGFILE
echo "`date` : Backup started." >> $LOGFILE
do_rsync
if [ $? -eq 0 ] ; then
echo "OK. Backup succeeded" | tee -a $LOGFILE
do_accounting $MAILADDR
exit 0
else
echo "Backup failed. See $LOGFILE for debug info." | tee -a $LOGFILE
do_accounting $MAILADDR
exit 1
fi
else
echo "$EXCLUDES_LIST: File not found or not a regular file. Backup aborted" | tee -a $LOGFILE;
exit 1
fi
else
echo "$BACKUP_LIST: File not found or not a regular file. Backup aborted" | tee -a $LOGFILE
exit 1
fi
else
echo "You must edit the script file and set the variable EXCLUDES_LIST" | tee -a $LOGFILE
exit 1
fi
else
echo "You must edit the script file and set the variable BACKUP_LIST" | tee -a $LOGFILE
exit 1
fi
exit 2

Que va-til arriver avec l'historique?
Salut, merci pour ton script. C'est une très bonne adaptation. Je peux te fournir mon correctif que j'ai ajouter pour backuper sur la même machine au lieux de passer par ssh. Ça peut-être pratique pour un serveur qui est déja backuper. Par exemple, mes serveurs sont backuper sur tape 1 fois par semaine. J'utilise donc rsync pour avoir un backup incremental à chaque jour. De cette façon, mon backup sur tape 1 fois par semaine va contenir un backup de chaque jour également.
Ma question est la suivante: Si j'ai bien compris ton script, il créer une version incremental par jour et un full par semaine. Le problème c'est que je ne vois rien qui supprime les semaines précédentes Tu aura donc à la fin de l'année un backup full des 52 semaines? Exact? C'est ce que tu souhaite?
Dans mon cas, tous ce que j'ai besoin c'est de conserver la semaine courante (La semaine qui précèdre la journée de mon backup full fait par le tape backup.)
Tu as une idée comment je pourrais implémenter ça tout en respectant ton script?
Merci!
Carl
Implémentation de la rétention
Bonjour Carl,
C'est vrai que le script ne gère pas la suppression des anciennes backups. Une façon qui me semble correcte pour le faire est de déclarer une variable qui définira le délai de rétention et une variable qui contiendra le nom du dossier de sauvegarde à supprimer, dans ton cas pour une rétention d'une semaine:
RETENTION=1
WEEK_NUM_OLD=`expr $WEEK_NUM - $RETENTION`
ARCHIVE_DIR_OLD="$ARCHIVE_ROOT/$HOSTNAME/`date +%Y`-$WEEK_NUM_OLD"
ensuite après le succès de la backup actuelle on supprime la plus ancienne backup:
...
if [ $? -eq 0 ] ; then
echo "OK. Backup succeeded" | tee -a $LOGFILE
do_accounting $MAILADDR
exit 0
rm -rf $ARCHIVE_DIR_OLD
else
...
Le problème ici c'est si la backup actuelle est celle de la première semaine de l'année ou en général si la variable WEEK_NUM_OLD contient une valeur négative. Dans ce cas, on peut faire le test suivant avant de renseigner ARCHIVE_DIR_OLD:
if [ $WEEK_NUM_OLD -ge 1 ] ; then
ARCHIVE_DIR_OLD="$ARCHIVE_ROOT/$HOSTNAME/`date +%Y`-$WEEK_NUM_OLD"
else
ARCHIVE_DIR_OLD="$ARCHIVE_ROOT/$HOSTNAME/`expr $(date +%Y) - 1`-`expr 52 + $WEEK_NUM_OLD`"
fi
Ou quelque chose de semblable. A tester!
Pour ton script de sauvegarde sur tape, çà serait sympa de me l'envoyer en me disant si je peux le publier sur le site.
sauvegarde
bonjour.
j'ai suivie votre scripte sur la Sauvegarde incrémentale de fichiers avec RSYNC et SSH.
je dois faire une erreur je n'ai pas d'erreur sauf le mail que j'ai mis en commentaire.
j'ai un message comme quoi la auvegarde c'est bien passé, mais je n'ai pas de fichier dans la sauvegarde.
j'aimerai sauvegarder la totalité du disque.
j'ai mis :
BACKUP_ROOT=/
BACKUP_LIST="/Users/mika/Documents/backup1/backup_list.txt"
dans backup_list il y a rien. comme je veux tout sauvegarder.
EXCLUDES_LIST="/Users/mika/Documents/backup1/backup_exclude"
est également vide.
Bonjour, backup_list.txt ne
Bonjour,
backup_list.txt ne peut pas être vide, il devrait contenir les dossiers à sauvegarder. J'ai pas essayé mais met un * dans le fichier. Si çà marche pas essaye ceci: modifie la chaine suivante: "--files-from=$BACKUP_LIST" et met à sa place celle ci: "--include-from=$BACKUP_LIST" en gardant le caractère * dans ton backup_list.txt.
Poster un nouveau commentaire