LXD 4.0 natively supports virtual machines and thanks to a built-in agent, can have them behave almost like containers.
We are producing VM images daily for the following distributions:
- Arch Linux
- CentOS (7 and up)
- Debian (8 and up)
For those that have
cloud variants for container images, they have matching
cloud variants for VM too.
Those images are currently the preferred ones for all of those distributions as they are automatically tested daily and also include support for the LXD agent out of the box.
You can also use the official Ubuntu images, with availability matching that of containers.
Note that those images currently do not include a fully functional LXD agent, so additional work is needed to have them behave.
Creating a VM is as simple as:
lxc launch images:ubuntu/focal ubuntu --vm
lxc launch images:centos/9-Stream centos --vm
For official Ubuntu images, cloud-init must be used along with a config drive to seed a default user into the VM and allow console access. This is done with:
lxc init ubuntu:18.04 ubuntu --vm ( cat << EOF #cloud-config apt_mirror: http://us.archive.ubuntu.com/ubuntu/ ssh_pwauth: yes users: - name: ubuntu passwd: "\$6\$s.wXDkoGmU5md\$d.vxMQSvtcs1I7wUG4SLgUhmarY7BR.5lusJq1D9U9EnHK2LJx18x90ipsg0g3Jcomfp0EoGAZYfgvT22qGFl/" lock_passwd: false groups: lxd shell: /bin/bash sudo: ALL=(ALL) NOPASSWD:ALL EOF ) | lxc config set ubuntu user.user-data - lxc config device add ubuntu config disk source=cloud-init:config lxc start ubuntu
You can see your VM boot with:
lxc console NAME
(detach with ctrl+a-q)
Once booted, VMs with the agent built-in will also respond to:
lxc exec NAME bash
For the official Ubuntu images, the agent needs to be manually enabled by logging in through
lxc console. The credentials in the example above are
Once logged in, run:
mount -t 9p config /mnt cd /mnt ./install.sh reboot
(Note that this part will slowly become un-necessary. The 20.04 images should already have this done and so have
lxc exec just work after boot.)
Virtual machines respect most of the usual instance settings as listed in the documentation.
You can attach
disk devices to them, grow their CPU & RAM, take snapshots, move them between hosts, use them in a cluster, publish them as images, …
They should pretty much all behave as you would expect a LXD instance, just a bit slower because you’re dealing with a full virtual machine.
It is possible to build Windows images for LXD, but this process is currently very very manual and involves either a bunch of custom
raw.qemu flags to get a temporary graphical console to perform the install or using a separate QEMU process to prepare the image.
The basic steps are:
- Grab a Windows ISO image from Microsoft
- Install distrobuilder:
snap install distrobuilder --classic
- Repack your ISO with: distrobuilder repack-windows /path/to/iso win.iso
- Create an empty VM with beefier CPU/RAM and SecureBoot disabled:
lxc init win10 --empty --vm -c security.secureboot=false -c limits.cpu=4 -c limits.memory=4GB
- Grow its root disk to a reasonable size:
lxc config device override win10 root size=20GB
- Add the ISO as boot drive:
lxc config device add win10 install disk source=/path/to/win.iso boot.priority=10
- Start the VM:
lxc start win10 --console
- Repeatedly hit ESC in that console (even before any output) to enter the firmware menu.
Boot Managerand then the
QM00001drive. Then hit ENTER a few times to answer an invisible boot prompt.
- Disconnect using
- Use the VGA console with
lxc console win10 --type=vga, you’ll see the installer boot
- Once installed you can remove the install drive with:
lxc config device remove win10 install
- Boot the system to confirm it all works, install all the other drivers from the virtio drive, then run the Windows sysprep tool
- Finally publish your VM as an image with:
lxc publish win10 --alias win10
- Community images are only available for x86_64 and aarch64
- Some distributions are not Secure Boot enabled, this will show up as a boot failure with something along the lines of
Access Denied. For those, secureboot must be disabled with
lxc config set NAME security.secureboot false, then the VM started again.