Quick and dirty script for making cold backups of KVM Virtual Machines

Note that this depends on “virsh”, the libvirt client, and “bzip2”.

Basically, what this script does is send a shutdown signal to each of the specified nodes, back up the disk images, and then bzip them in the background while it restarts the node. So having said this, you’ll want to make sure your services on your VM’s are set to shut down and start up gracefully when the OS is shut down / restarted.



#!/bin/bash

#
# This is who we'll back up
#
machines="Dev Test Foobar"

#
# Keep the house clean
#
days_to_keep="7"

#
# Store backups here. NFS to another machine would make sense. 
# so that your backups are not local.
#
backup_dir="/VirtualMachines/KVM/backups"

#
# Logs go here.
#
log_dir="/VirtualMachines/KVM/backups/logs"

#
# End parameters
#
#=================================================================

#
# Timestamp for the log file
#
right_now=`date '+%m%d%Y_%H%M%p'`

exec 1>/${log_dir}/backup_vms.${right_now}.log 2>&1

print_date() {
   date '+%m%d%Y_%H%M%p'
}

for machine in $machines
do
   if [[ ! -d ${backup_dir}/${machine} ]];
   then
      mkdir -p ${backup_dir}/${machine}
   fi

   echo "Backing up VM configuration"
   virsh dumpxml $machine > ${backup_dir}/${machine}/${machine}.xml

   echo "Sending shutdown signal to $machine"
   virsh shutdown $machine
   echo "   Return code: $?"
   
   echo -n "Waiting for machine to shut down "
   for i in 1 2 3 4 5
   do
      echo -n "."
      virsh list | grep -v "^$" | grep -v "^ Id" | grep -v "\-\-\-\-\-" | awk '{print $2" "$3}' | grep $machine | while read name state
      do
         if [[ $state -eq "running" ]]
         then
            sleep 60
         fi
      done
   done

   echo "Copying disk(s)"
   virsh domblklist $machine | grep -v "^$" | grep -v "^Target" | grep -v "\-\-\-\-\-" | awk '{print $2}' | while read disk
   do
      echo "   $disk ..."
      copy_disk="${backup_dir}/${machine}/`basename ${disk}`.`print_date`"
      echo "   Copying $disk to $copy_disk"
      fuser $disk 1>/dev/null 2>&1
      if (( $? == 0 ))
      then
         echo "   Disk $disk is still in use! "
      else
         echo "   Copy started at `print_date`"
         cp $disk $copy_disk
         echo "   Return code: $?"
         echo "   Copy ended at `print_date`"
         echo "   Backgrounding bzip of $copy_disk"
         nohup bzip2 $copy_disk &
      fi
   done

   echo "Starting machine $machine"
   virsh start $machine
   echo "   Return code: $?"
   echo

done

   echo "Removing old backups."
   find $backup_dir -type f -mtime +$days_to_keep -ls
   find $backup_dir -type f -mtime +$days_to_keep -exec rm -f {} \;

8 thoughts on “Quick and dirty script for making cold backups of KVM Virtual Machines

  1. Thanks for this script.
    I should mention that if you have an ISO attached to the VM image then these will get backed up as well. So unattach any ISO before running it.
    Also, to take backup of the VM configuration file add the following to your script:

    virsh dumpxml vm_name > /tmp/vm_name.xml

    cheers…

  2. Very nice script!! Exactly what i needed. 1 small remark that would make it perfect : if the “logs” directory doesn’t exist it would be nice to create it on the first run :)))

    For compression bzip works fine in the background but a full uncompressed copy of the disk image can be slow if you copy the image externally. I have several images with quite a bit of empty space in the image, I now use pigz (multi-threaded compression) and do copy and compression on the fly using tar.gz. With the VM in shutdown state i can use full cpu capacity to compress the images. The copy operation saturates my ethernet link, using on the fly compression doesn’t even drive cpu utllization of the Dual 6-core server to 100% but still saturates the ethernet link (so the compression is just extra speed).

    Your mileage may vary 🙂

    Thanks for this very,very useful script, i couldn’t have made it myself!

  3. Is it possible to add an exclusion option on the disk images? I have backup images named “vmname-BACKUP01” etc which are located on NAS mounts (these are normally used for backup routines inside the guest OS) Backing these up along with the cold host isn’t needed. Is adding an exclusion for disk images containing BACKUP in their names possible?
    Thanks for an excellent script, way above my ability for sure.

Leave a Reply

Your email address will not be published.