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