I knew I’d come across something like this before …
I think you might be able to do it with rdiff
(see man rdiff
)
From my reading of the man page, where the VM vol is /working/vm.qcow2
# save starting state ( vm 0 )
cp /working/vm.qcow2 /backup/vm-0.qcow2
rdiff signature /working/vm.qcow2 /backup/vm-0.signature
# backup 1 (vm 1)
rdiff delta /backup/vm-0.signature vm.qcow2 /backup/1.delta # delta = change between vm-0 and current vm
rdiff signature /working/vm.qcow2 /backup/vm-1.signature
# backup 2 (vm 2)
rdiff delta /backup/vm-1.signature vm.qcow2 /backup/2.delta # delta = change between vm-1 and current vm
rdiff signature /working/vm.qcow2 /backup/vm-2.signature
# recover
rdiff patch /backup/vm-0.qcow2 /backup/1.delta /recovered/vm-1.qcow2
rdiff patch /recovered/vm-1.qcow2 /backup/2.delta /recovered/vm-2.qcow2
I haven’t tested any of the above as to whether it works or not…
but here’s some output for an idea of times (Intel® Xeon® CPU E5-2620 v3 @ 2.40GHz, 32GB ) and file/delta sizes:
[root@devpc vmStorage]# ls -lashi fedora-server-base.qcow2
136 31G -rwxrwxrwx. 1 qemu qemu 31G Apr 23 09:51 fedora-server-base.qcow2
[root@devpc vmStorage]# time -p rdiff signature fedora-server-base.qcow2 sigtest
real 185.09
user 71.60
sys 7.73
[root@devpc vmStorage]# time -p rdiff delta sigtest fedora-server-base.qcow2 delta
real 185.27
user 74.38
sys 7.81
[root@devpc vmStorage]# ls -lashi
...
144 1.4M -rw-r--r--. 1 root root 1.4M Apr 23 11:11 delta
136 31G -rwxrwxrwx. 1 qemu qemu 31G Apr 23 09:51 fedora-server-base.qcow2
143 6.3M -rw-r--r--. 1 root root 6.3M Apr 23 11:00 sigtest
...
There were no changes to the file so the 1.4M delta was a surprise - I have no idea how rdiff works its magic.
All that said, I use rdiff-backup
which alas works the wrong way round for you / VMs in that it stores the latest as a full copy and deltas going back in time - very handy if you want to pull the last backup - its just a file copy.
I’m in a similar situation to yourself and I agree with @iwalker. I’m going to keep the same process for backups on VMs as I have on bare metal : the machine backs up to its own backup device (real or virtual) using rdiff-backup and then rsyncs that (the local backup) to a removable/offsite/rotated backup - a real disk where the VM can write via NFS/Samba or another virtual disk file (alas filesystem passthru not avail on RHEL).
EDIT
If you still want to go with backing up the VM as opposed to the files then an alternative to rdiff above would be to use a backed qcow2 image and back that up each day before commiting it to the main image. Along with the original main image you could recover to any of the backed files.
EDIT 2
(on backing up the (shutdown) VM virtual disk / volume as opposed to the files … and selling rdiff-backup )
Thinking about it some more… I suspect that rdiff-backup …
initially copies the whole file to backup copy A and then on subsequent backups …
1.copies the (“reverse”) delta between the current file and A to the backup and then
2.rsyncs the diffs between the current file and A to update A to be the same as the current file.
In which case rdiff-backup would only ever rsync the changes (albeit twice) to the backup and then the user, using rsync (or rdiff-backup) to revert, would only be rsyncing the file diffs back.
That would seem sensible and is my best guess at what happens.
If that is the case then rdiff-backup should do incremental backups and reverts just moving the diffs (twice for backups or pre-last restores).
To date I’ve only ever restored by directly rsyncing the top level/most recent backup to where I needed it as opposed to using rdiff-backup to do a restore (eg. of a previous backup).
The time to process (altered) large files (~30GB+) and work out the diffs is noticable though it hasn’t been a problem.
So you could just use rdiff-backup instead of rdiff (above) and get the generally preferable situation where you only have to restore incrementally as you go back in time.
That said, the simplest way to do incremental backups on virtual disks is probably using backed qcow2 files (shutdown, backup live qcow2 file, commit it to backing qcow2 file, restart).
EDIT 3 (DOH !)
Of course the rdiff approach involves transfering signatures too and depending on how it works/is configured etc. rdiff-backup may have to read the whole last-state backup file each time to do the calcs so, depending on specifics, data transfer costs might include significantly more than the deltas. Similar may apply to rsyncing a file-level backup. The qcow2s though only involve pushing/pulling the “changes” ( … E&OE / caveat emptor etc. )
EDIT 4 (DOH ! - there’s no need to store signatures with rdiff method)
# save starting state ( vm 0 )
cp /working/vm.qcow2 /backup/vm-0.qcow2
rdiff signature /working/vm.qcow2 /working/vm-last-bu.signature
# backup 1 (vm 1)
rdiff delta /working/vm-last-bu.signature /working/vm.qcow2 /backup/1.delta # delta = change between vm-0 and current vm
rdiff -f signature /working/vm.qcow2 /working/vm-last-bu.signature
# backup 2 (vm 2)
rdiff delta /working/vm-last-bu.signature /working/vm.qcow2 /backup/2.delta # delta = change between vm-1 and current vm
rdiff -f signature /working/vm.qcow2 /working/vm-last-bu.signature
# recover
cp /backup/vm-0.qcow2 /recovered/vm-0.qcow2
rdiff patch /recovered/vm-0.qcow2 /backup/1.delta /recovered/vm-1.qcow2
rdiff patch /recovered/vm-1.qcow2 /backup/2.delta /recovered/vm-2.qcow2
So, just the diffs. Again, not tested.
In the other direction / rdiff with reverse diffs…
# save current state ( vm )
cp /working/vm.qcow2 /backup/vm.qcow2
cp /working/vm.qcow2 /working/vm-last-bu.qcow2
# backup 1 (vm 1)
rdiff -f signature /working/vm.qcow2 /working/vm.signature
rdiff delta /working/vm.signature /working/vm-last-bu.qcow2 /backup/1.delta
rsync /working/vm.qcow2 /backup/vm.qcow2
cp -f /working/vm.qcow2 /working/vm-last-bu.qcow2
# backup 2 (vm 2)
rdiff -f signature /working/vm.qcow2 /working/vm.signature
rdiff delta /working/vm.signature /working/vm-last-bu.qcow2 /backup/2.delta
rsync /working/vm.qcow2 /backup/vm.qcow2
cp -f /working/vm.qcow2 /working/vm-last-bu.qcow2
# recover
rsync /backup/vm.qcow2 /working/vm.qcow2 # last backup state
rdiff patch /working/vm.qcow2 /backup/2.delta /working/vm-2.qcow2 # 1 increment back
mv -f /working/vm-2.qcow2 /working/vm.qcow2
rdiff patch /working/vm.qcow2 /backup/1.delta /working/vm-1.qcow2 # 2 increment back
mv -f /working/vm-1.qcow2 /working/vm.qcow2
So, the (reverse) diffs AND rsyncing the “head” AND keeping a local copy of the file.
Again, not tested.