Sauvegarder sur bandes ses machines virtuelles

Pour limiter le nombre serveurs à utiliser et d’isoler les différents services, je découpe l’ensemble à l’aide de machines virtuelles Xen. La machine hôte fournis une partition LVM pour chacune de ses machines. La question se pose alors de comment sauvegarder l’ensemble en conservant la cohérence des données.

Principe

Nous aborderons une solution simple pour sauvegarder un ensemble de partitions LVM. Nous nous appuierons sur les subtilités de LVM et de ses snapshots

LVM et Les snapshots

Avant d’aborder les snapshots (copie de volume), il faut rapidement rappeler comment fonctionne LVM.

LVM agrège un ensemble de disques dur physiques et fournit un groupe de volumes logiques. Ce sont les volumes logiques qui seront vu par le système.

Ces volumes logiques stockent les données à l’aide des extent ce sont des blocs de données réservés. LVM essaiera toujours d’écrire l’ensemble des donnés d’un fichier dans le même extent. Cette approche limite la fragmentation. Enfin pour chaque volume, un tableau de description est présent pour indiquer l’ensemble des états de tous les extent.

Dans le cas d’un snapshot (cliché), comme on pourrait l’imaginer ce n’est pas une réplique exacte qui est faite. Le snapshot copie la description des états de tous les extent du volume d’origine. Un snapshot gère uniquement les différences entre elle et son volume père.

Lorsque le volume d’origine est modifié, l’extent qui supporte ces données est copié avant modification dans le snapshot. Le tableau de description est mis à jour en conséquence. Le snapshot ainsi conserve l’état du volume père au moment de sa création.

Cette approche permet de créer des volumes de taille inférieure au volume d’origine tout en gardant l’intégrité des données. Selon les documentations on peut considérer que la taille du snapshot peut faire dans les 15 à 20% du volume d’origine.

Pour se faire une idée plus claire et en images, je vous invite à consulter le site de Suno Ano.

Le script de backup

La partie du script spécifique à la sauvegarde profite pleinement du travail réalisé par Vivek Gite. On trouvera quel que ajustements déjà présenté dans le forum de sa page mais non intégré dans le script original.

Les fonctions de gestions des partitions

L’originalité de ce script repose sur la création et le montage des snapshot.

Nous avons un lot de fonctions :

  • snapshot_create()
  • snapshot_remove()
  • snapshot_create_all()
  • snapshot_remove_all()

Les 2 premières s’occupent de gérer la création, suppression d’un volume donné ainsi que son (dé)montage. Les 2 autres font appel aux précédentes pour gérer un lot de volume à sauvegarde.

« snapshot_create() » est surement la fonction la plus intéressante. Son travail consiste à créer une partition de type snapshot.
Il n’est pas nécessaire de faire une copie de taille identique, et il est pertinent d’optimiser l’occupation de la machine hôte. Ainsi la fonction calcule la taille du snapshot à hauteur de 20% (ratio empirique) du volume père. On notera une subtilité avec la gestion des langues, ceci est du au format de retour de certaines des fonctions appelées (bc et lvs) qui diffère selon la langue active.
Cette taille peut être largement réduite en fonction de l’espace disponible sur votre serveur et de la quantité de modifications de données au moment de la sauvegarde.

En prenant en compte tous ces détails, nous obtenons un script qui tourne en production sans problèmes.

Le script complet

#!/bin/bash
# Original script provided by Vivek Gite <vivek@nixcraft.com>
# -------------------------------------------------------------------------
# Copyright (c) 1999 Vivek Gite <vivek@nixcraft.com>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
# Last updated on : March-2003 - Added log file support.
# Last updated on : Feb-2007 - Added support for excluding files / dirs.
# -------------------------------------------------------------------------
# Actual script adapted by Camille Lafitte
# <cam.lafit@azerttyu.net>
# -------------------------------------------------------------------------
# Last updated on Dec 2009 : Add mail notification from Vivek forum ( backup_notify )
# Last updated on Dec 2009 : Mange date by number for better i18n support
# Last updated on Dec 2009 : Add LVM snapshots support ( snapshot_* functions )
#
# A UNIX / Linux shell script to backup dirs to tape device like /dev/st0 (linux)
# This script make both full and incremental backups.
# You need at two sets of five  tapes. Label each tape as Mon, Tue, Wed, Thu and Fri.
# You can run script at midnight or early morning each day using cronjons.
# The operator or sys admin can replace the tape every day after the script has done.
# Script must run as root or configure permission via sudo.
#
# Script to backup a group of LVM volumes on tape device
# -------------------------------------------------------------------------
LOGBASE=/var/log/tar_back

#LV to backup
LV_NAME="vg00/machine1 vg00/machine2 vg01/machine1"

# Backup dirs; do not prefix /
BACKUP_ROOT_DIR="mnt/snapshots/"
BACKUP_SNAP_DIR="/mnt/snapshots"

# Get todays day like Mon, Tue and so on
NOW=$(date +"%w")

#Mail notifier
MAIL_NOTIFIER="c.lafitte@dombox.fr"

# Tape devie name
TAPE="/dev/st0"

# Exclude file
TAR_ARGS=""
EXCLUDE_CONF=/root/.backup.exclude.conf

# Backup Log file
LOGFILE=$LOGBASE/$NOW.backup.log

# Path to binaries
export PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:$PATH

TAR=/bin/tar
MT=/bin/mt
MKDIR=/bin/mkdir


# ------------------------------------------------------------------------
# Excluding files when using tar
# Create a file called $EXCLUDE_CONF using a text editor
# Add files matching patterns such as follows (regex allowed):
# home/vivek/iso
# home/vivek/*.cpp~
# ------------------------------------------------------------------------
[ -f $EXCLUDE_CONF ] && TAR_ARGS="-X $EXCLUDE_CONF"

#### Custom functions #####
# Make a full backup
full_backup(){
        local old=$(pwd)
        cd /
        $TAR $TAR_ARGS -cvpf $TAPE $BACKUP_ROOT_DIR > $LOGFILE 2>&1
        backup_notify $?
        $MT -f $TAPE rewind
        $MT -f $TAPE offline
        cd $old
}

# Make a  partial backup
partial_backup(){
        local old=$(pwd)
        cd /
        $TAR $TAR_ARGS -cvpf $TAPE -N yesterday $BACKUP_ROOT_DIR > $LOGFILE 2>&1
        backup_notify $?
        $MT -f $TAPE rewind
        $MT -f $TAPE offline
        cd $old
}

# Make sure all dirs exits
verify_backup_dirs(){
        local s=0
        for d in $BACKUP_ROOT_DIR
        do
                if [ ! -d /$d ];
                then
                        echo "Error : /$d directory does not exits!"
                        s=1
                fi
        done
        # if not; just die
        [ $s -eq 1 ] && exit 1
}

snapshot_create_all() {

        for d in $LV_NAME
        do
                if [ ! -d /$d ];
                then
                        OIFS=$IFS
                        IFS='/'
                        d=( $d )
                        snapshot_create ${d[0]} ${d[1]}
                        IFS=$OIFS
                fi
        done
}

snapshot_create(){

        OLD_LANG=$LANG
        LANG=en_us.8859_1

        VG=$1
        LV=$2
        #Taille de la partition en Mo
        SIZE=`lvs /dev/$VG/$LV -o lv_size --noheadings --units M --nosuffix`
        SIZE=${SIZE// /}

        SNAP_SIZE=$(echo "scale=2;x = $SIZE * 20 / 100;x" | bc)

        if [ ! -d /dev/$VG/$LV ]
        then
                lvcreate -L"$SNAP_SIZE"M -s -n $LV.snap "/dev/$VG/$LV"
                LANG=$OLD_LANG
       
                fsck "/dev/$VG/$LV.snap"
                mkdir -p "$BACKUP_SNAP_DIR/$LV"
                mount "/dev/$VG/$LV.snap" "$BACKUP_SNAP_DIR/$LV"
        fi
}

snapshot_remove_all(){

       for d in $LV_NAME
       do
               if [ ! -d /$d ];
               then
                       OIFS=$IFS
                       IFS='/'
                       d=( $d )
                       snapshot_remove ${d[0]} ${d[1]}
                       IFS=$OIFS
               fi
       done
}

snapshot_remove(){
        VG=$1
        LV=$2

        umount "$BACKUP_SNAP_DIR/$LV"
        lvremove "/dev/$VG/$LV.snap" -f
}

backup_notify(){
       local s=$1
       if [ $s -eq 0 ]
       then
                echo $LOGFILE |mailx -s "Backup Successfully done @ $(hostname)" $MAIL_NOTIFIER #< $LOGFILE
       else
                echo $LOGFILE |mailx -s "Backup FAILED @ $(hostname)" $MAIL_NOTIFIER #< $LOGFILE
       fi
}


#### Main logic ####

# Make sure log dir exits
[ ! -d $LOGBASE ] && $MKDIR -p $LOGBASE

# Verify dirs
verify_backup_dirs

# Okay let us start backup procedure
# If it is monday make a full backup;
# For Tue to Fri make a partial backup
# Weekend no backups

snapshot_create_all
#Pas de backup le mecredi
case $NOW in
        1|4)        full_backup;;
        2|5)         partial_backup;;
        *) ;;
esac
#esac > $LOGFILE 2>&1

snapshot_remove_all

Un message, un commentaire ?

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.