How to Convert a Directory into QEMU/KVM Bootable Virtual Disk Image


3 views

Many tutorials cover converting physical disks to virtual images, but transforming a directory structure into a bootable virtual disk presents unique challenges. The key steps involve:

  1. Creating a properly sized virtual disk container
  2. Formatting it with a filesystem
  3. Mounting both the virtual disk and source directory
  4. Copying contents while preserving permissions

Here's the complete workflow I've tested on Ubuntu 22.04 LTS:


# 1. Create raw disk image (adjust size as needed)
qemu-img create -f raw disk.img 10G

# 2. Format the image (ext4 example)
mkfs.ext4 disk.img

# 3. Create mount points
mkdir /mnt/vdisk /mnt/source

# 4. Mount both devices
mount -o loop disk.img /mnt/vdisk
mount --bind /var/backups/disk1 /mnt/source

# 5. Copy contents (rsync preserves permissions)
rsync -avxHAX /mnt/source/ /mnt/vdisk/

# 6. Cleanup
umount /mnt/vdisk
umount /mnt/source

For better storage efficiency with KVM/QEMU:


# Convert raw to qcow2 format
qemu-img convert -f raw -O qcow2 disk.img disk.qcow2

# Optional: Compress the image
qemu-img convert -c -O qcow2 disk.qcow2 disk_compressed.qcow2

For repeated conversions, save this as dir_to_vdisk.sh:


#!/bin/bash
SOURCE_DIR="$1"
OUTPUT_FILE="$2"
SIZE_GB="${3:-10}" # Default 10GB

# Create and format image
qemu-img create -f raw "$OUTPUT_FILE.raw" "${SIZE_GB}G"
mkfs.ext4 "$OUTPUT_FILE.raw"

# Mount and copy
mkdir -p /mnt/vdisk /mnt/source
mount -o loop "$OUTPUT_FILE.raw" /mnt/vdisk
mount --bind "$SOURCE_DIR" /mnt/source
rsync -avxHAX /mnt/source/ /mnt/vdisk/

# Convert to qcow2
qemu-img convert -f raw -O qcow2 "$OUTPUT_FILE.raw" "$OUTPUT_FILE.qcow2"

# Cleanup
umount /mnt/vdisk
umount /mnt/source
rm "$OUTPUT_FILE.raw"

Test your new image with QEMU:


qemu-system-x86_64 -enable-kvm -m 2048 \
  -drive file=disk.qcow2,format=qcow2

When dealing with virtual machines, there are situations where you need to convert an existing directory structure (containing a complete filesystem) into a bootable virtual disk image. This differs significantly from physical disk conversion because:

  • We're working with files rather than block devices
  • The directory lacks partition table and boot sector information
  • Filesystem metadata needs proper reconstruction

Here's the complete workflow to create a bootable virtual disk from your directory:

# Create raw image file
dd if=/dev/zero of=vmdisk.img bs=1M count=2048

# Format with filesystem
mkfs.ext4 vmdisk.img

# Mount and copy files
mkdir /mnt/vmdisk
mount -o loop vmdisk.img /mnt/vmdisk
rsync -a /var/backups/disk1/ /mnt/vmdisk/
umount /mnt/vmdisk

# Convert to QCOW2 format
qemu-img convert -f raw -O qcow2 vmdisk.img vmdisk.qcow2

For simpler cases, the virt-make-fs tool from libguestfs can handle this in one command:

virt-make-fs --format=qcow2 --size=+2G /var/backups/disk1 vmdisk.qcow2

To make the image properly bootable, you'll need to:

  1. Install bootloader (GRUB):
  2. mount -o loop vmdisk.img /mnt/vmdisk
    grub-install --root-directory=/mnt/vmdisk --no-floppy --target=i386-pc vmdisk.img
    umount /mnt/vmdisk
  3. Ensure proper fstab entries:
  4. echo "/dev/vda1 / ext4 defaults 0 1" >> /mnt/vmdisk/etc/fstab

Test your new image with QEMU:

qemu-system-x86_64 -enable-kvm -m 2048 -hda vmdisk.qcow2

For production environments, consider these optimizations:

  • Use virt-sparsify to shrink the image
  • Enable compression during conversion: qemu-img convert -c -O qcow2
  • Preallocate space with fallocate for better performance