User Tools

Site Tools


backup_linux_kvm_par_snap

Sauvegarde KVM à chaud par Snap

Le but est de minimiser les temps d'arrêt application des VM pour faire un backup, voici les étapes.

  • Le chemin vers le fichier disk, est obtenu par virsh domblklist domain.
  • Je vais utiliser la commande snapshot-create-as de virsh pour faire le snap.
  • Le fichier disk principal n'est plus soumis aux écritures une fois le snap en place, je vais le sauvegarder via tar.
  • Le répertoire de snap doit être sur le même disque que le volume de la vm (à vérifier, j'avais eu des problème).
  • Une fois le backup effectué, je fais un virsh blockcommit pour revenir en écriture sur le volume d'origine de la vm.
  • Le fichier snap peut être effacé.

J'ai essayé de rendre un peu plus robuste le script, il reste peut être des coquilles. J'utilise une debian 12.12 à ce jour.

Pour lancer un backup, lancer le script avec en paramètre le fichier environnement.

Par exemple:

  • backup_vm.sh opnsense.env

Fichier environnement

BACKUP_PATH="/mnt/backup_vm/kvm"
SNAP="/mnt/kvm/.snapshot"
DOMAIN=opnsense
MAIL_FROM="__EMAIL__"
MAIL_TO="__EMAIL__"
MAIL_SUBJECT="KVM backup"

Script de backup

#!/bin/bash
#

HOT=1 #backup a chaud

if [ $# -ne 1 ]; then
        echo "Arguments error"
        exit 1
fi

if [ ! -f "$1" ]; then
    echo "File '$1' does not exist"
    exit 1
fi

source $1

if [ ! -d $BACKUP_PATH ]; then
    echo "Directory '$BACKUP_PATH' does not exist "
    exit 1
fi

if [ ! -d $SNAP ]; then
    echo "Directory '$SNAP' does not exist "
    exit 1
fi

virsh domuuid $DOMAIN
if [ $? -ne 0 ]; then
    echo "Domain '$DOMAIN' does not exist "
    exit 1
fi

if [ ! -d $BACKUP_PATH/$DOMAIN ]; then
        echo "Directory '$BACKUP_PATH/$DOMAIN' does not exist "
        echo "Create directory $BACKUP_PATH/$DOMAIN"
        mkdir $BACKUP_PATH/$DOMAIN
fi

#check if domain is running
if [ "$( LANG=C virsh domstate $DOMAIN )" != "running" ]; then
    echo "Domain $DOMAIN not start - Cold backup mode"
    HOT=0 #on backup a froid
fi


EXTENSION=$(virsh domblklist "$DOMAIN" --details | awk '$2=="disk" {n=split($4,a,"."); print a[n]}')
BACKUPDATE=$(date "+%Y-%m-%d.%H%M%S")
TARGET=$(virsh domblklist "$DOMAIN" --details | awk '$2=="disk" {print $3}')
DISK=$(virsh domblklist "$DOMAIN" --details | awk '$2=="disk" {print $4}')
SNAPFILE=${SNAP}/${DOMAIN}-snapshot-${BACKUPDATE}.${EXTENSION}
BACKUP_DOMAIN=${BACKUP_PATH}/${DOMAIN}
DISKSPEC="--diskspec ${TARGET},file=${SNAPFILE},snapshot=external"
MESSAGE=""
STATUS=""

send_mail()
{
  printf "From: $MAIL_FROM\nTo: $MAIL_TO\nSubject: $MAIL_SUBJECT : $STATUS\n\n$MESSAGE\n" | msmtp $MAIL_TO
}

echo "creation du repertoire de sauvegarde ${BACKUP_DOMAIN}"
#creation du repertoire de sauvegarde
mkdir -p ${BACKUP_DOMAIN}
virsh dumpxml ${DOMAIN} > ${BACKUP_DOMAIN}/${BACKUPDATE}-${DOMAIN}.xml
if [ $? -ne 0 ]; then
    echo "Failed to dumpxml $DOMAIN"
    MESSAGE="Failed to dumpxml $DOMAIN"
    STATUS="ERROR"
    send_mail
    exit 1
fi

if [ "$HOT" -eq 1 ]; then
        echo "creation du snap ${DOMAIN}-snapshot-${BACKUPDATE}"
        #creation du snap
        virsh snapshot-create-as --domain ${DOMAIN} --name ${DOMAIN}-snapshot-${BACKUPDATE} --no-metadata --atomic --disk-only ${DISKSPEC}
        if [ $? -ne 0 ]; then
                echo "Failed to create snapshot for $DOMAIN"
                MESSAGE="Failed to create snapshot for $DOMAIN"
                STATUS="ERROR"
                send_mail
                exit 1
        fi
fi

# On affiche le disk actif en écriture pour la vm, le snap normalement
virsh domblklist ${DOMAIN}

echo "copy ${DISK} to ${BACKUP_PATH}/${DOMAIN}/${BACKUPDATE}-${DOMAIN}.${EXTENSION}"
#copy
#cp ${DISK} ${BACKUP_PATH}/${DOMAIN}/${BACKUPDATE}-${DOMAIN}.${EXTENSION}
_FILE=${BACKUP_PATH}/${DOMAIN}/${BACKUPDATE}-${DOMAIN}.${EXTENSION}
#zpaq a ${_FILE}.zpaq ${DISK} -m2
tar --zstd -cvf ${_FILE}.tar.zstd ${DISK}
if [ $? -ne 0 ]; then
    echo "Failed to copy ${DISK} to ${_FILE}"
    MESSAGE="Failed to copy ${DISK} to ${_FILE}"
    STATUS="ERROR"
    send_mail
    exit 1
fi

if [ "$HOT" -eq 1 ]; then
        echo "retour sur snap blockcommit ${DOMAIN}"
        #On arrêt le snap pour revenir écrire sur le disk d'origine
        virsh blockcommit ${DOMAIN} ${TARGET} --active --pivot
        if [ $? -ne 0 ]; then
                echo "Failed to blockcommit snapshot for $DOMAIN"
                MESSAGE="Failed to blockcommit snapshot for $DOMAIN"
                STATUS="ERROR"
                send_mail
                exit 1
        fi
fi

# On affiche le disk actif en écriture pour la vm, le disk d'origine
virsh domblklist ${DOMAIN}

echo "delete snap file $SNAPFILE"
#on peut delete le snap
if [ "$HOT" -eq 1 ]; then
        rm $SNAPFILE
fi

#test de l'archive
#zpaq x ${_FILE}.zpaq -test
tar --zstd -tvf ${_FILE}.tar.zstd
if [ $? -ne 0 ]; then
    echo "Failed : archive test ${_FILE}"
    MESSAGE="Failed test file : {_FILE}"
    STATUS="ERROR"
    send_mail
    exit 1
fi

MESSAGE="${MAIL_SUBJECT} [OK] Domain: $DOMAIN"
STATUS="OK"
send_mail

echo "[OK] - Status - Backup completed"
exit
backup_linux_kvm_par_snap.txt · Last modified: by ppj