In a previous post, I showed how to set up KVM and Cockpit on Ubuntu 24.04.
That setup works well for creating and managing virtual machines from a browser. However, after running several VMs, the host system disk can fill up quickly.
In my case, my existing VMs were using the default libvirt image directory:
/var/lib/libvirt/images/
Later, I added an external USB hard disk and wanted to move some existing VM disk images to it.
This post shows how to create a new libvirt storage pool on the external disk and move an existing KVM VM disk image from the default storage location to the new storage pool.
Prerequisite: Existing KVM and Cockpit Setup
This post assumes that KVM, libvirt, and Cockpit are already installed and working on the Ubuntu host.
If you have not set up KVM and Cockpit yet, follow my previous post first:
How to Set Up KVM and Cockpit on Ubuntu 24.04
In that setup, VM disk images are stored in the default libvirt image directory:
/var/lib/libvirt/images/
This post continues from that environment and focuses only on adding a new storage pool and moving existing VM disk images to it.
Environment
In this example, I am using:
Host OS: Ubuntu 24.04
Virtualization: KVM / QEMU / libvirt
Management UI: Cockpit
External disk mount point: /mnt/data
New storage pool name: usb-vm-storage
VM name: client
Original VM disk: /var/lib/libvirt/images/client.qcow2
New VM disk path: /mnt/data/libvirt/images/client.qcow2
The same process can be repeated for other VMs.
Current Situation Before Moving the VM
First, list the existing VMs:
sudo virsh list --all
Example output:
Id Name State
-----------------------------
17 harbor running
18 zabbix running
25 jenkins running
28 artifactory running
30 osm running
33 mumble running
34 proxy running
35 client running
In this example, I will move the client VM first.
Check the disk used by the VM:
sudo virsh domblklist client --details
Example output:
Type Device Target Source
----------------------------------------------------------------
file disk vda /var/lib/libvirt/images/client.qcow2
The VM currently uses this disk image:
/var/lib/libvirt/images/client.qcow2
The goal is to move it to:
/mnt/data/libvirt/images/client.qcow2
- Confirm the External Disk Is Mounted
First, confirm that the external disk is mounted:
findmnt /mnt/data
df -h /mnt/data
Example output:
TARGET SOURCE FSTYPE OPTIONS
/mnt/data /dev/sda1 ext4 rw,relatime,stripe=8191
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 916G 2.1M 870G 1% /mnt/data
In this case, the external disk is mounted at:
/mnt/data
It is also formatted as ext4, which is suitable for storing KVM qcow2 images.
I do not recommend storing active VM disk images on NTFS or exFAT. For KVM/libvirt on Linux, use a Linux filesystem such as ext4 or xfs.
- Make Sure the External Disk Is Persistently Mounted
Before using the disk for VM storage, make sure it is mounted automatically after reboot.
Check /etc/fstab:
grep /mnt/data /etc/fstab
If there is no entry, get the UUID of the partition:
sudo blkid /dev/sda1
Then edit /etc/fstab:
sudo vi /etc/fstab
Add an entry similar to this:
UUID=your-disk-uuid /mnt/data ext4 defaults,nofail,x-systemd.device-timeout=10 0 2
Replace your-disk-uuid with the real UUID from blkid.
Then test the mount:
sudo mount -a
df -h /mnt/data
Do not continue until the disk mounts correctly.
If the disk is not mounted after reboot, any VM stored on it will not be able to start.
- Create a Directory for VM Images
Create a directory for VM disk images on the external disk:
sudo mkdir -p /mnt/data/libvirt/images
Set the owner and permissions:
sudo chown -R libvirt-qemu:kvm /mnt/data/libvirt
sudo chmod 755 /mnt/data
sudo chmod 755 /mnt/data/libvirt
sudo chmod 770 /mnt/data/libvirt/images
This allows QEMU/libvirt to access the VM disk images.
- Create a New libvirt Storage Pool
Create a new directory-based libvirt storage pool:
sudo virsh pool-define-as usb-vm-storage dir --target /mnt/data/libvirt/images
sudo virsh pool-build usb-vm-storage
sudo virsh pool-start usb-vm-storage
sudo virsh pool-autostart usb-vm-storage
Verify the storage pools:
sudo virsh pool-list --all
sudo virsh pool-info usb-vm-storage
Example output:
Name State Autostart
--------------------------------------
images active yes
usb-vm-storage active yes
Name: usb-vm-storage
UUID: a569e69a-cdb7-4a5a-b414-5dbeda4b292a
State: running
Persistent: yes
Autostart: yes
Capacity: 915.82 GiB
Allocation: 2.04 MiB
Available: 915.81 GiB
At this point, libvirt can use the external disk as a storage pool.
The original default pool remains unchanged, and the new pool is available separately.
- Check the Existing VM Disk Path
Check the disk used by the VM you want to move:
sudo virsh domblklist client --details
Example output:
Type Device Target Source
----------------------------------------------------------------
file disk vda /var/lib/libvirt/images/client.qcow2
This confirms that the client VM is still using the original disk image under:
/var/lib/libvirt/images/
- Check for Snapshots or Backing Files
Before moving a qcow2 file, check whether the VM has snapshots:
sudo virsh snapshot-list client
Example output:
Name Creation Time State
-------------------------------
An empty list means there are no libvirt snapshots.
Next, check whether the qcow2 file has a backing chain:
sudo qemu-img info --backing-chain /var/lib/libvirt/images/client.qcow2
If the VM is still running, you may see this error:
qemu-img: Could not open '/var/lib/libvirt/images/client.qcow2': Failed to get shared "write" lock
Is another process using the image [/var/lib/libvirt/images/client.qcow2]?
This is normal when the VM is running. The disk image is locked because QEMU is using it.
Shut down the VM before checking the image and copying it.
- Shut Down the VM
Gracefully shut down the VM:
sudo virsh shutdown client
Check the VM state:
sudo virsh domstate client
Expected output:
shut off
Now check the qcow2 file again:
sudo qemu-img info --backing-chain /var/lib/libvirt/images/client.qcow2
Example output:
image: /var/lib/libvirt/images/client.qcow2
file format: qcow2
virtual size: 150 GiB (161061273600 bytes)
disk size: 144 GiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false
Child node '/file':
filename: /var/lib/libvirt/images/client.qcow2
protocol type: file
file length: 144 GiB (155106541568 bytes)
disk size: 144 GiB
In this example, there is no backing file line, so the VM uses a single qcow2 file.
If you see a backing file, do not blindly copy only the top qcow2 file. You need to handle the whole backing chain.
- Copy the VM Disk to the New Storage Pool
Copy the disk image to the new location:
sudo rsync -aHAX --sparse --progress \
/var/lib/libvirt/images/client.qcow2 \
/mnt/data/libvirt/images/
This may take some time depending on the VM disk size and the speed of the external disk.
After copying, fix the ownership:
sudo chown libvirt-qemu:kvm /mnt/data/libvirt/images/client.qcow2
Refresh the storage pool:
sudo virsh pool-refresh usb-vm-storage
Confirm that the file exists:
ls -lh /mnt/data/libvirt/images/client.qcow2
sudo virsh vol-list usb-vm-storage
- Back Up the VM XML
Before changing the VM configuration, back up the current XML:
sudo virsh dumpxml client > ~/client-before-move.xml
This gives you a copy of the original VM configuration in case you need to compare or restore it later.
- Update the VM Disk Path
Edit the VM configuration:
sudo virsh edit client
Find the original disk source:
<source file='/var/lib/libvirt/images/client.qcow2'/>
Change it to the new path:
<source file='/mnt/data/libvirt/images/client.qcow2'/>
The disk section should look similar to this:
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/mnt/data/libvirt/images/client.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
If the VM was created through Cockpit, you may also see Cockpit metadata like this:
<cockpit_machines:install_source>/var/lib/libvirt/images/client.qcow2</cockpit_machines:install_source>
You can update it too:
<cockpit_machines:install_source>/mnt/data/libvirt/images/client.qcow2</cockpit_machines:install_source>
The important part for booting the VM is the disk source under the <devices> section:
<source file='/mnt/data/libvirt/images/client.qcow2'/>
To replace all matching paths in vi, you can use:
:%s#/var/lib/libvirt/images/client.qcow2#/mnt/data/libvirt/images/client.qcow2#g
Then save and quit:
:wq
- Confirm the VM Uses the New Disk Path
After saving the XML, check the VM disk path again:
sudo virsh domblklist client --details
Expected output:
Type Device Target Source
-----------------------------------------------------------------
file disk vda /mnt/data/libvirt/images/client.qcow2
This confirms that the VM now points to the disk image on the new storage pool.
- Start the VM
Start the VM:
sudo virsh start client
Check the state:
sudo virsh domstate client
Expected output:
running
Check the disk path again:
sudo virsh domblklist client --details
Example output:
Type Device Target Source
-----------------------------------------------------------------
file disk vda /mnt/data/libvirt/images/client.qcow2
After confirming that the VM starts correctly and uses the new disk path, keep the old qcow2 file for a while as a fallback. Do not delete the old disk image until you have verified that the VM boots and works normally.

353

被折叠的 条评论
为什么被折叠?



