How to Spawn Virtual Machines from Disk Images in Ubuntu Using systemd-vmspawn

Modern Linux testing and continuous integration workflows demand rapid, isolated execution environments. While container engines like Docker or systemd-nspawn provide lightweight namespace isolation, they share the host kernel, preventing tests that require custom kernel modules, hypervisor hardware abstraction, or distinct storage architectures. Setting up full-scale virtualization suites like libvirt, KVM virt-manager, or cloud-init can be cumbersome for quick testing sessions. In recent systemd versions, the systemd-vmspawn tool bridges this gap by acting as a native virtual machine manager that boots raw OS disk images, raw partitions, and directory trees inside QEMU virtual machines using standard systemd invocation semantics.

Understanding systemd-vmspawn and QEMU Virtualisation

The systemd-vmspawn command provides a direct virtual machine counterpart to systemd-nspawn:

  • True Hardware Virtualisation: Instead of creating a Linux namespace container, systemd-vmspawn orchestrates QEMU/KVM under the hood to spin up an authentic hardware-isolated virtual machine with its own virtualised kernel, memory, and devices.
  • Direct Image Booting: Boots raw GPT disk images, raw squashfs images, and Unified Kernel Images (UKIs) conforming to the Discoverable Partitions Specification (DPS).
  • Shared Journal Logging: Forwards the guest virtual machine console and journal logs directly to the host terminal or journal daemon.
  • Container-Like Ergonomics: Starts, stops, and coordinates virtual machines with single-line commands without requiring XML configuration files or background hypervisor daemons.

Installing Prerequisites on Ubuntu

Because systemd-vmspawn delegates low-level virtualisation tasks to QEMU and KVM hardware accelerators, ensure the necessary virtualization packages are installed on Ubuntu:

sudo apt update
sudo apt install qemu-system-x86 qemu-utils ovmf systemd-container

Verify that hardware virtualisation extensions (Intel VT-x or AMD-V) are enabled on your system CPU:

egrep -c '(vmx|svm)' /proc/cpuinfo

A return value greater than 0 confirms hardware acceleration support. Ensure your current user belongs to the kvm group:

sudo usermod -aG kvm $USER

Booting a Disk Image Using systemd-vmspawn

To launch a virtual machine from an existing raw or QCOW2 operating system disk image (such as an Ubuntu Cloud image or custom appliance), use systemd-vmspawn -i:

sudo systemd-vmspawn -i ubuntu-noble-server-cloudimg.img

The tool automatically allocates virtual CPU cores, attaches the disk image as a virtual block device, invokes QEMU with KVM acceleration, and attaches your active terminal to the guest serial console.

To specify explicit CPU and memory allocations, use the --cpus and --ram switches. For example, to assign 4 virtual CPU cores and 4 GB of RAM:

sudo systemd-vmspawn --cpus=4 --ram=4096 -i ubuntu-noble-server-cloudimg.img

Booting a Directory Tree as a Virtual Machine

Similar to systemd-nspawn -D, systemd-vmspawn can boot directly into a root filesystem directory tree on the host without packaging it into a virtual disk first. It creates a temporary virtual block device or exports the filesystem via 9p / virtio-fs:

sudo systemd-vmspawn -D /srv/test-rootfs/

This allows developers to inspect, modify, and test root filesystem images on the host disk while booting them with complete virtual kernel isolation.

Configuring Virtual Machine Networking

By default, systemd-vmspawn establishes a user-mode virtual network (SLIRP) or virtual tap interface for the guest:

  • Default User Mode: Provides outbound network access (DNS, HTTP/HTTPS) without requiring bridge setup on the host.
  • Port Forwarding: To expose guest network ports (such as SSH on port 22 or a web server on port 8080) to the host system, specify the --port argument:
    sudo systemd-vmspawn --port=2222:22 -i ubuntu-noble-server-cloudimg.img
  • You can then connect directly to the guest VM from your workstation terminal:
    ssh -p 2222 user@localhost

Managing and Monitoring Active Virtual Machines

Virtual machines launched with systemd-vmspawn register with the systemd machine manager, allowing you to interrogate them using machinectl:

machinectl list

The output displays the active VM, its operational class (vm), hypervisor backend (qemu), and internal OS version.

To inspect resource consumption, memory allocation, and CPU load for the running virtual machine:

machinectl status ubuntu-noble-server-cloudimg

To gracefully shut down or terminate the guest virtual machine from another terminal:

sudo machinectl poweroff ubuntu-noble-server-cloudimg

To force-terminate an unresponsive guest:

sudo machinectl terminate ubuntu-noble-server-cloudimg

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.