When migrating KVM VMs between standalone hosts, you'll need to transfer two critical components:
- Virtual disk images (typically qcow2 or raw format)
- VM configuration XML (from virsh dumpxml)
Here's the complete workflow for a successful migration:
1. Prepare the Source VM
First, shutdown the VM cleanly on the source host:
virsh shutdown vm_name
virsh list --all # Verify shutdown status
2. Locate and Transfer Disk Files
Find the disk paths from the VM config:
virsh dumpxml vm_name | grep "source file"
Then transfer using rsync (recommended for large files):
rsync -avzP /var/lib/libvirt/images/vm_disk.qcow2 \
user@dest-host:/var/lib/libvirt/images/
3. Export and Transfer VM Configuration
virsh dumpxml vm_name > vm_name.xml
scp vm_name.xml user@dest-host:~/
4. On Destination Host
Define and start the VM:
virsh define vm_name.xml
virsh start vm_name
virsh list --all
For production environments, consider these enhancements:
Network Configuration Alignment
Edit the XML before defining to match destination network names:
<interface type='network'>
<source network='dest-bridge-name'/>
</interface>
Performance Optimization
Use parallel transfer with multiple rsync sessions:
rsync -avzP --bwlimit=100M /path/to/disks/ \
user@dest-host:/path/to/destination/
- Permission errors: Ensure libvirt-qemu user has access to disk files
- UUID conflicts: Remove or modify uuid in XML if migrating clones
- Failed starts: Check logs with
journalctl -u libvirtd
For minimal downtime, consider these approaches:
# Live block copy (requires short downtime)
virsh blockcopy vm_name vda --dest /new/path/image.qcow2 --wait --verbose
When moving KVM virtual machines between hosts that don't share storage, we need to handle both the VM configuration and disk images manually. This process is common in environments where centralized storage solutions like NFS or iSCSI aren't available.
First, identify your VM components:
virsh list --all
virsh dumpxml vm_name > vm_name.xml
For disk images, locate their paths in the XML configuration or use:
qemu-img info /path/to/disk.qcow2
You'll need to move two critical components:
- The XML configuration file (vm_name.xml)
- The disk image file(s) (disk.qcow2)
Use rsync for efficient transfer:
rsync -avzP /path/to/disk.qcow2 destination_host:/path/to/destination/
rsync -avzP vm_name.xml destination_host:/path/to/destination/
First, define the storage pool where disk images will reside:
virsh pool-define-as --name default --type dir --target /var/lib/libvirt/images
virsh pool-start default
virsh pool-autostart default
Then import the VM:
virsh define /path/to/destination/vm_name.xml
Check the imported VM configuration:
virsh dominfo vm_name
virsh dumpxml vm_name
Start the VM and verify operation:
virsh start vm_name
virsh console vm_name
Common problems and solutions:
- Disk path mismatch: Edit the XML file before defining
- Network configuration: Verify bridge names match
- UUID conflicts: Generate new UUID with
uuidgen
Example of XML modification for new paths:
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/new/path/to/disk.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
For larger environments, consider:
- Using virt-v2v for conversions
- Implementing incremental transfers with
qemu-img rebase
- Exploring libvirt's native migration capabilities with tunnelling
# Example of preparing for incremental transfer
qemu-img create -f qcow2 -b source.qcow2 new.qcow2
Optimize transfer speed with:
- Compression (use -z with rsync)
- Parallel transfers for multiple disks
- Network tuning (MTU, TCP windows)
Example of parallel transfer with GNU parallel:
parallel -j 4 rsync -avzP {} destination_host:/path/ ::: disk1.qcow2 disk2.qcow2