Storage and Disk Management
MicroVM uses virtio-blk-device for block storage. This article covers disk image management, multiple drives, and I/O optimization.
Storage Types
Raw Disk Image
The simplest format with the best performance:
# Create a 10GB raw image
qemu-img create -f raw data.img 10G
# Check the info
qemu-img info data.img
QCOW2 Image
A format with snapshot and thin provisioning features:
# Create a QCOW2 image
qemu-img create -f qcow2 data.qcow2 10G
# With compression
qemu-img create -f qcow2 -o compression_type=zstd data.qcow2 10G
Format Comparison
| Feature | Raw | QCOW2 |
|---|---|---|
| I/O performance | Best | Slightly slower |
| Dynamic sizing | No | Yes |
| Snapshots | No | Yes |
| Encryption | No | Yes |
| Compression | No | Yes |
Multiple Drives
MicroVM supports multiple virtio-blk-devices (limited to a maximum of 8 virtio devices in total):
# Rootfs + Data disk
qemu-system-x86_64 \
-M microvm -enable-kvm -cpu host -m 256m -smp 2 \
-kernel vmlinuz \
-append "console=ttyS0 root=/dev/vda rw" \
-drive id=rootfs,file=rootfs.img,format=raw,if=none \
-device virtio-blk-device,drive=rootfs \
-drive id=data,file=data.img,format=raw,if=none \
-device virtio-blk-device,drive=data \
-nographic -serial stdio
Inside the Guest
# Check the block devices
lsblk
# Output:
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
# vda 252:0 0 2G 0 disk
# └─vda1 252:1 0 2G 0 part /
# vdb 252:16 0 10G 0 disk
# Mount the data disk
mkdir -p /data
mount /dev/vdb /data
# or with a fresh filesystem
mkfs.ext4 /dev/vdb
mount /dev/vdb /data
# Add to fstab
echo "/dev/vdb /data ext4 defaults,noatime 0 2" >> /etc/fstab
Host Disk Passthrough
Access a physical host disk directly from the MicroVM:
# Pass through the whole disk
qemu-system-x86_64 \
-M microvm -enable-kvm -cpu host -m 512m \
-kernel vmlinuz \
-append "console=ttyS0 root=/dev/vda rw" \
-drive id=rootfs,file=rootfs.img,format=raw,if=none \
-device virtio-blk-device,drive=rootfs \
-drive id=hostdisk,file=/dev/sdb,format=raw,if=none \
-device virtio-blk-device,drive=hostdisk \
-nographic -serial stdio
Passthrough via LVM
# Create an LVM volume for the VM
sudo lvcreate -L 10G -n vm-data vg0
# Pass through to QEMU
-drive id=lvmdata,file=/dev/vg0/vm-data,format=raw,if=none \
-device virtio-blk-device,drive=lvmdata
NFS Mount (Network Storage)
Mount an NFS share from the host into the guest:
# Set up an NFS server on the host
sudo apt install nfs-kernel-server
echo "/srv/nfs 10.0.0.0/24(rw,sync,no_subtree_check)" | sudo tee -a /etc/exports
sudo exportfs -ra
# In the guest, mount the NFS share
apt install nfs-common # Debian
mount -t nfs 10.0.0.1:/srv/nfs /mnt/nfs
Overlay Filesystem
Use an overlay for an efficient rootfs (read-only base image):
# Create the base image (read-only)
qemu-img create -f raw base-rootfs.img 1G
mkfs.ext4 base-rootfs.img
# ... install the OS into base-rootfs.img
# Create the overlay image
qemu-img create -f raw overlay-rootfs.img 2G
# In the guest, mount with overlay
mount -t overlay overlay -o \
lowerdir=/,upperdir=/overlay/upper,workdir=/overlay/work \
/merged
I/O Optimization
Cache Mode
# None (direct I/O) - best performance
-drive id=rootfs,file=rootfs.img,format=raw,if=none,cache=none
# Writeback - buffering on the host
-drive id=rootfs,file=rootfs.img,format=raw,if=none,cache=writeback
# Writethrough - safe, sync writes
-drive id=rootfs,file=rootfs.img,format=raw,if=none,cache=writethrough
AIO Mode
# Linux AIO for async I/O
-drive id=rootfs,file=rootfs.img,format=raw,if=none,aio=linux
# io_uring (QEMU >= 6.0, Linux >= 5.1)
-drive id=rootfs,file=rootfs.img,format=raw,if=none,aio=io_uring
Discard/TRIM
# Enable discard for SSD thin provisioning
-drive id=rootfs,file=rootfs.img,format=raw,if=none,discard=unmap
# Or QCOW2
-drive id=rootfs,file=rootfs.qcow2,format=qcow2,if=none,discard=unmap
Optimization Script
#!/bin/bash
# Script: run-microvm-optimized.sh
KERNEL="./vmlinuz"
ROOTFS="./microvm-rootfs.img"
exec qemu-system-x86_64 \
-M microvm,pit=off,pic=off,rtc=off \
-enable-kvm \
-cpu host \
-m 512m \
-smp 4 \
-kernel "$KERNEL" \
-append "console=ttyS0 root=/dev/vda rw elevator=noop" \
-drive id=rootfs,file="$ROOTFS",format=raw,if=none,cache=none,aio=linux,discard=unmap \
-device virtio-blk-device,drive=rootfs \
-netdev tap,id=net0,script=no,downscript=no \
-device virtio-net-device,netdev=net0 \
-nographic -serial stdio
Backup and Restore
Backup Raw Image
# Live backup with dd
dd if=/dev/vda of=backup.img bs=4M status=progress
# Or with qemu-img
qemu-img convert -f raw -O raw rootfs.img backup.img
# Compressed backup
dd if=rootfs.img bs=4M | gzip > rootfs.img.gz
Backup QCOW2
# Export to raw for backup
qemu-img convert -f qcow2 -O raw rootfs.qcow2 backup.img
# or back up directly
cp rootfs.qcow2 rootfs.backup.qcow2