KVM External Snapshots (and Backups) Part 1 – using virsh blockcommit

Today we will look at using external KVM snapshots to create backup images of guest VMs. While external snapshot support in KVM is not as mature compared to internal ones, it is faster to execute while the VM is running and more flexible in terms of generated snapshot files. Here in Part 1 we will be using virsh blockcommit command which allows us to keep the original base image after flattening.

In this example, I am using a VM guest (or virsh domain) with name centos7.0. First, let’s check what disk is being used:

virsh domblklist centos7.0

Look for the entry under “Target”. In my case this is sdb. Take note of the “Source” entry as well, which for now is the original base image /mnt/vm/QEMU/centos.qcow2. Now let’s proceed and create an external snapshot and generate a new active image called overlay.qcow2:

virsh snapshot-create-as –domain centos7.0 centos-state01 –diskspec sdb,file=/mnt/vm_snapshots/centos7.0/overlay.qcow2 –disk-only –atomic

This snapshot execution will take no time at all. You cannot generate it this quickly with internal snaphots. You can also place the overlay file wherever you want – you are not stuck with the original qcow2 image.

Now check the image currently in use, the “Source” entry should now be switched to /mnt/vm_snapshots/centos7.0/overlay.qcow2:

virsh domblklist centos7.0

From here you can safely backup the original base image, copy/rsync to your backup directory:

cp /mnt/vm/QEMU/centos.qcow2 /mnt/backup/centos7.0-20190916.qcow2

Now that we have our backup, lets combine/flatten the snapshot back to the base image using the magic of virsh blockcommit:

virsh blockcommit centos7.0 sdb –active –verbose –pivot

Let’s check the current image in use, should have reverted back to the original base image:

virsh domblklist centos7.0

The “Source” should now be back to /mnt/vm/QEMU/centos.qcow2.

The next step is to delete the snapshot. Because of incomplete support for KVM external snapshots, you cannot just do a virsh snapshot-delete; that only works for internal snapshots.

First let’s delete the XML metadata of the snapshot using the –metadata option:

virsh snapshot-delete centos7.0 –metadata –current

Now we can physically delete the overlay file we created:

rm /mnt/vm_snapshots/centos7.0/overlay.qcow2

There you have it, we have (1) created an external snapshot, (2) backed up our image file, (3) flattened the overlay back to the base image, and (4) cleaned up the overlay file and snapshot metadata. All this without any downtime/pausing of the VM. Maybe we can create a bash script to automate this later on.

Further reading: Red Hat Documentation

Creating a Linux Bridge in NetworkManager (and use it for KVM guests)

When creating VMs using libvirt, you can always use the default networking setup. The guests will use a dedicated domain, usually 192.168.122.0/24. However this has one big limitation – the other machines outside of the host cannot communicate with the guests. I have seen some solutions to workaround this, but then you have to configure each guest to accept packets coming in from outside the host. What I want to do here is to simplify the set-up and have the guests reside in the same domain as the host, and this can be done by creating a bridge.

If you are using NetworkManager, you can create the bridge from your host via the GUI provided by the nm-applet. In this example I am using lxqt, you can adapt it to your desktop environment. You can also do this via nmcli commands if you wish.

Right click on the nm-applet icon in your panel notification area. Choose ‘Edit Connections…’, click the plus/add sign, and choose ‘Bridge’ under the Virtual connections.

You can leave the default options as is. Take note of the interface name, here it is ‘bridge0’ – you will use this when creating NICs for your VMs. Under ‘General’ tab enable ‘Connect Automatically’ and disable STP in the ‘Bridge’ tab (up to you if you want these options – STP is not needed in my set-up and it takes some time to start up if enabled).

Under ‘Bridged Connections’ click on ‘Add’, pick ‘Ethernet’ and then ‘Create’, and choose the ethernet device that you want to be the bridge slave. You can adjust link negotiation fields here for your chosen interface.

Save, and now you have a working bridge for your host. To use it for your VMs in libvirt virtmanager GUI (I use the virtio device, it works well for me):

Here’s the xml snippet:

Now your guest will connect to your domain via this bridge.

Note: If you are having issues on the bridge connection especially after the next startup – most likely it is because the bridge is being defined but the related modules are not yet loaded. Here is what I did as per the libvirt documentation. First add the following to your sysctl conf file – In my case (Arch Linux), I put these in the /etc/sysctl.d/99-sysctl.conf:

net.bridge.bridge-nf-call-arptables = 0
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0

Now to be sure the bridge modules are loaded at startup, I added the following through /etc/modules-load.d/bridge.conf file (of course you can name it any way you want just make sure you put a .conf extension):

bridge
br_netfilter

Restart, and check to see if your bridge now works as intended.

Additional reading: libvirt wiki