Featured image of post Backup KVM machines using btrfs snapshots

Backup KVM machines using btrfs snapshots

I just wrote a small Bash script for creating offline-backups of a bunch of virtual machines on a server using btrfs snapshots.

The script shuts all running KVM machines gracefully down, waits until they are turned off, creates a (read-only) btrfs snapshot and spins the machines back on. All together takes less than a minute. After the process I have an image of all my virtual machines in the state, when the machines are shut down. This is then suitable for storing the machine image files on a different machine to have a complete working state of the machines. This is part of my backup strategy for one of our general infrastructure servers at work.

The VM disk images need to be in a btrfs subvolume, otherwise it doesn’t work.

See the script on GitHub. You will need to do some adjustments and probably test it a couple of times, but then it works nicely :-)


#!/bin/bash
# Shell script to stop all KVM instances, create a BTRFS snapshot (read-only) and restart the stopped KVM instances
# https://gist.github.com/grisu48/535c27cd25c096248ce234ad81abf1b9

## Configuration ##############################################################

IMGDIR="/mnt/RAID/libvirt/images"
SNAPDIR="/mnt/RAID/libvirt/snapshots"
# timeout in seconds
TIMEOUT=300

## Script #####################################################################

running_domains() {
        virsh list | grep running | awk '{print $2}'
}




# Get all virtual machines that are currently running
VMACH="$(running_domains)"

# Shutdown machines
for i in $VMACH; do
        virsh shutdown "$i"
done

# Wait for machines to shut down
END_TIME=$(date -d "$TIMEOUT seconds" +%s)
while [ $(date +%s) -lt $END_TIME ]; do
        test -z "$(running_domains)" && break
        sleep 1         # Prevent busy waiting
done
# Check for still running machines (i.e. timeout)
if [ -n "$(running_domains)" ]; then
        echo "Timeout while shutting down"
        exit 1
fi


# Create snapshot
SNAPSHOT="${SNAPDIR}/`date --iso`"
if [ -d "$SNAPSHOT" ]; then
        echo "Overwriting existing snapshot $SNAPSHOT"
        btrfs subvolume delete "$SNAPSHOT"
fi
btrfs subvolume snapshot -r "$IMGDIR" "$SNAPSHOT"
status=$?

# Bring machines back online
for i in $VMACH; do
        virsh start "$i"
        if [ $? -ne 0 ]; then
                echo "Failed to start $i"
                status="1"
        fi
done

exit $status