• Ce blog — désormais archivé — est en lecture seule.

Sauvegarde incrémentale avec rsync : fichiers et base de données MySQL

Bonjour, suite à mon passage en dédié (Dédibox v3) et à sa configuration aujourd’hui terminée, j’ai trouvé nécessaire de m’occuper de la sauvegarde des données. Pour cela, je me suis aidé de plusieurs sources :

Sauvegarde des bases MySQL

Je sauvegarde toutes les bases de données sur une durée d’une semaine. Voici le script, il est possible de le coupler à un envoi de la sauvegarde via FTP. Je conserve ainsi toutes mes sauvegardes sur un serveur distant et complètement déconnecté de ce dont je vais vous parler ensuite.

#!/bin/bash

#---------------------------------------------------------------#
# Paramétrage de la connection MySQL                            #
#---------------------------------------------------------------#

#Nom de l'utilisateur qui lance le backup
user=<user>
#Machine sur laquelle on se connecte
host=<host>
#Mot de passe de l'utilisateur de backup
pass=<password>

# Outil de dump
MYSQLDUMP=mysqldump
#Outil de check
MYSQLCHECK=mysqlcheck
# Options passées à MYSQLDUMP
OPTIONS="--add-drop-database  --add-drop-table --complete-insert --routines --triggers --max_allowed_packet=250M --force"

#---------------------------------------------------------------#
# Paramétrage de la sauvegarde                                  #
#---------------------------------------------------------------#

# Répertoire temporaire pour stocker les backups
TEMPORAIRE="/tmp/bkp_mysql"

# Nom du serveur
MACHINE="$(hostname)"

# Date courante
DATE="$(date +"%d-%m-%Y")"
# Date de conservation maximum
DATE2=`date --date '1 week ago' "+%d-%m-%Y"`

# Nom des fichiers de backup
# Répertoire de destination du backup
DESTINATION="/home/backuper/mysql"
FICHIER_BACKUP=$MACHINE"_BACKUP_MYSQL_"$DATE".tar.gz"
FICHIER_EFFACER=$MACHINE"_BACKUP_MYSQL_"$DATE2".tar.gz"

#Informations FTP
LOGIN_FTP=<user_ftp>
PASS_FTP=<pass_ftp>
HOST_FTP=<host_ftp>

#---------------------------------------------------------------#
# Process de sauvegarde                                         #
#---------------------------------------------------------------#

# Création du répertoire temporaire
if [ -d $TEMPORAIRE ];
then
  echo "Le repertoire temporaire existe.";
else
  mkdir $TEMPORAIRE;
fi

# On construit la liste des bases de données
BASES="$(mysql -u $user -h $host -p$pass -Bse 'show databases')"

# On lance le dump des bases
for db in $BASES
do
  #On lance un check et une analyse pour chaque base de données
  $MYSQLCHECK -u $user -h $host -p$pass -c -a $db
  # On lance un mysqldump pour chaque base de données
  $MYSQLDUMP -u $user -h $host -p$pass $OPTIONS $db -R > $TEMPORAIRE"/"$MACHINE"-"$db"-"$DATE".sql";
done

# Création de l'archive contenant tout les dump
#Cette archive est stockée dans le dossier défini pour la sauvegarde
if [ -d $DESTINATION ];
then
    cd $TEMPORAIRE
    tar -cvzf $DESTINATION"/"$FICHIER_BACKUP *
fi

# On transfere l'archive par FTP
cd $DESTINATION
ftp -v -n $HOST_FTP < <SCRIPT
user $LOGIN_FTP $PASS_FTP
bin
put $FICHIER_BACKUP
bye
SCRIPT

# On supprime le fichier de plus de x jours
if [ -f $DESTINATION"/"$FICHIER_EFFACER ]; then
    rm $DESTINATION"/"$FICHIER_EFFACER
fi

# On suprime le répertoire temporaire
if [ -d fichier ]; then
  rm -Rf $TEMPORAIRE
fi

Sauvegarde incrémentale des fichiers avec rsync

Je sauvegarde mes fichiers à la semaine de la façon suivante :

  • sauvegarde dans un répertoire nommé : <Année>-<Numéro de semaine>
  • dans ce répertoire j’ai un dossier main qui contient l’intégralité des fichiers. Cette sauvegarde est faite le lundi.
  • j’ai 6 répertoires nommés : <jour>_<date au format jj-mm-aaaa> contenant les sauvegardes incrémentales de la semaine.

J’ai modifié le script pour ajouter une conservation des sauvegardes de 4 semaines.

#!/bin/bash

# - 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_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
BACKUP_ROOT=/
BACKUP_LIST="/home/backuper/scripts/backup_list_files"

# 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="/home/backuper/scripts/backup_exclude_files"

# Hostname or IP adress of the remote backup server
BACKUP_SRV=

# Port SSH
SSH_PORT=

# Root directory that stores backups on the remote server
ARCHIVE_ROOT=~/files

# Remote user. Used by ssh. This is the user who connects to the remote backup server
# Must have write access on $ARCHIVE_ROOT
REMOTE_USER=

# 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=

# Log file
LOGFILE="/home/backuper/backup-files.log"

# HOSTNAME
#  This is used for creating a directory specific to this host on the remote host
HOSTNAME="$(hostname)"

#########################################
# From here on out, you probably don't  #
#   want to change anything unless you  #
#   know what you're doing.             #
#########################################

if [ -f $LOGFILE ]
then
  rm $LOGFILE
  touch $LOGFILE
fi

# 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()
{
   if [ $SSH_PORT ] ; then
    rsync -e "ssh -p $SSH_PORT" $OPTIONS $BACKUP_ROOT $REMOTE_USER@$BACKUP_SRV:$ARCHIVE_DIR/$CURRENT >> $LOGFILE 2>&1
   else
    rsync $OPTIONS $BACKUP_ROOT $REMOTE_USER@$BACKUP_SRV:$ARCHIVE_DIR/$CURRENT >> $LOGFILE 2>&1
   fi
   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

    if [ $SSH_PORT ] ; then
      ssh -p $SSH_PORT $REMOTE_USER@$BACKUP_SRV du -s $ARCHIVE_DIR/* >> /tmp/rsync_script_tmpfile
    else
      ssh $REMOTE_USER@$BACKUP_SRV du -s $ARCHIVE_DIR/* >> /tmp/rsync_script_tmpfile
    fi

    echo >> /tmp/rsync_script_tmpfile
    cat $LOGFILE | grep "rsync: " >> /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
}

# Clean old backups
do_clean()
{
    # Nb weeks
    NB_WEEKS_MAX=4
    LIMIT=`expr $WEEK_NUM - $NB_WEEKS_MAX`

    if [ $LIMIT -le 0 ]
    then
        NB=`expr $NB_WEEKS_MAX - $WEEK_NUM`
        NB=`expr 52 - $NB`
        LAST_YEAR=`expr $(date +%Y) - 1`
        TO_DELETE_DIR="$ARCHIVE_ROOT/$HOSTNAME/$LAST_YEAR-$NB"

        if [ -d $TO_DELETE_DIR ] ; then
          echo "rm -rf $TO_DELETE_DIR"  
    rm -rf $TO_DELETE_DIR
        fi
    else
        TO_DELETE_DIR="$ARCHIVE_ROOT/$HOSTNAME/`date +%Y`-$LIMIT"

        if [ -d $TO_DELETE_DIR ] ; then
          echo "rm -rf $TO_DELETE_DIR"  
    rm -rf $TO_DELETE_DIR
        fi
    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
        if [ $SSH_PORT ] ; then
    ssh -p $SSH_PORT $REMOTE_USER@$BACKUP_SRV install -d $ARCHIVE_DIR/$CURRENT
  else
    ssh $REMOTE_USER@$BACKUP_SRV install -d $ARCHIVE_DIR/$CURRENT
  fi
        echo >> $LOGFILE
  echo "=========================================================" >> $LOGFILE
        echo "`date` : Backup started." >> $LOGFILE
        do_rsync
  if [ $? -eq 0 ] ; then
    echo "OK. Backup succeeded" | tee -a $LOGFILE
          do_clean
    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

Je sauvegarde ces fichiers :

var/www
var/log
etc/apache2
etc/apt/sources.list
etc/fstab
etc/crontab
etc/hostname
etc/hosts
etc/group
etc/memcached.conf
etc/mysql
etc/nginx
etc/php5
etc/phpmyadmin
etc/postfix
etc/ssh
etc/fail2ban
home

Et j’exclue ceux-là :

home/backuper/backup-files.log
home/backuper/files
etc/mysql/debian.cnf
etc/ssh/ssh_host*
etc/phpmyadmin/htpasswd.setup
.*_history
.Xauthority
.lesshst
.ssh

Automatisation

J’ai rajouté dans mon crontab, deux lignes pour lancer les sauvegardes différées de 2h :

0 1 * * * /home/backuper/scripts/backup_mysql.sh
0 3 * * * /home/backuper/scripts/backup_files.sh

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • FriendFeed
  • LinkedIn
  • MySpace
  • Netvibes
  • PDF
  • Ping.fm
  • RSS
  • Technorati
  • viadeo FR
  • Wikio
  • Yahoo! Buzz

Related Posts

Cet article a été publié dans Serveur, Sysadmin avec les mots-clefs : , , , . Bookmarker le permalien. Les commentaires et les trackbacks sont fermés.

9 commentaires

  1. Youbs
    Le 7 juillet 2010 à 14 h 49 min | Permalien

    Nice :)

    Je viens de me souvenir, j’utilise ça au taf pour faire de la synchro entre deux répertoires distants par ftp :

    - lftp (apt-get install lftp )
    - un petit script avec la commande qui va bien :

    lftp ftp://user:pass@host/ -e « mirror –delete /remote/dir /local/diry ; quit »

    en supposant que tu exécutes la commande sur la machine qui reçoit le backup,

    Si tu veux exécuter la commande sur la machine qui contient les fichiers à sauvegarder il y’a juste à ajouter l’option –reverse et inverser les répertoires :

    lftp ftp://user:pass@host/ -e « mirror –delete –reverse /local/dir /remote/dir ; quit »

    Bon c’est pas de la sauvegarde incrémentale ni rien, mais ça peut toujours dépanner :)

    • Le 7 juillet 2010 à 23 h 20 min | Permalien

      Ah merci, ça peut servir ça :)

  2. Mat
    Le 7 juillet 2010 à 15 h 10 min | Permalien

    Nice :)

    Perso je viens de mettre en place Duplicity pour faire des sauvegarde incrémentales, c’est du bonheur au niveau des features :)
    https://help.ubuntu.com/community/DuplicityBackupHowto

    Sinon y’a aussi backup-manager qui est très simple à utiliser, mais moins complet.

    • Le 7 juillet 2010 à 23 h 20 min | Permalien

      Je savais que j’aurais dû te poser la question avant ;)

  3. Le 7 août 2010 à 14 h 15 min | Permalien

    Bonjour,

    Merci pour le partage, une autre façon de faire serait de fusionner les deux scripts en un. Le dump de la base étant un fichier régulier, il pourra être transféré en SSH aussi comme les autres fichiers.

    • Le 10 août 2010 à 12 h 12 min | Permalien

      Oui bien évidemment, c’est ce que je fais. Mes sauvegardes de bases de données se font avant la sauvegarde des fichiers, ainsi je récupère tout :)

  4. Nusa
    Le 19 septembre 2011 à 12 h 05 min | Permalien

    Bonjour,

    Je teste actuellement votre script mais je suis confronté à 2 problèmes :

    Contexte : un serveur Ubuntu sauvegardé sur un NAS synology.

    Problème 1 :Le script n’arrive pas à créer les dossiers « hostname » et « numéro de semaine » : dossier « monserveur » et sous dossier « 2011-38″. Si je créé manuellement ces 2 entrées, tout va bien.

    Problème 2 : peut être la cause du 1 : lorsque je lance le script j’ai tout de suite le retour suivant :
    ash: install: not found

    D’avance merci pour votre retour.

    Nusa

  5. Nusa
    Le 19 septembre 2011 à 12 h 24 min | Permalien

    Pourriez vous m’expliquer cette fonction :

    if [ $SSH_PORT ] ; then
    ssh -p $SSH_PORT $REMOTE_USER@$BACKUP_SRV install -d $ARCHIVE_DIR/$CURRENT
    else
    ssh $REMOTE_USER@$BACKUP_SRV install -d $ARCHIVE_DIR/$CURRENT
    fi

    Je ne connaissais pas cet argument « install » sur une commande SSH.

    D’avance merci.

    Nusa

    • Le 19 septembre 2011 à 12 h 29 min | Permalien

      Bonjour,

      Cela permet de créer les dossiers si je me souviens bien.
      Je n’ai pas retouché à ce script depuis un moment, il fonctionne bien sur mes deux serveurs depuis plus d’un an.

      William

Un trackback

  1. [...] et passionné ! #Symfony #Diem #Git #Nginx #WebPerfsAller au contenuCV – Curriculum Vitae« Sauvegarde incrémentale avec rsync : fichiers et base de données MySQLDédibox v3 : Nginx + PHP-FPM + Apache2 + APC + Memcached + MySQLPar Will | Publié : 12 [...]