Test Ubuntu Core with QEMU

You can test Ubuntu Core without specific hardware from within a virtual machine, using either Multipass or QEMU (https://www.qemu.org/).

  • Multipass has integrated support for the latest Ubuntu Core images and is quicker to get started with
  • QEMU is more configurable and can boot either a supported image or a custom image, with or without TPM emulation and full disk encryption.

Using QEMU is covered below. For details on using Multipass, see Test Ubuntu Core with Multipass.

Test QEMU

To test Ubuntu Core with QEMU on Ubuntu, first install the qemu-kvm package and test it with kvm-ok (a utility that comes with the cpu-checker package):

sudo apt install qemu-kvm
$ kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

To ensure compatibility with the required UEFI features in Ubuntu Core, also install the OVMF package:

sudo apt install ovmf

Download the preferred Ubuntu Core image for your device platform. See Supported platforms for links to images.

By default, images are compressed with xz and can be expanded from the Linux command line with the following command:

xz -d <image-name>.img.xz

The above command will remove the original archive leaving only the uncompressed image which will change after being booted. To keep a copy of the original archive, add the -k argument.

Boot an Ubuntu Core image with QEMU

The exact QEMU command to run will depend on your host hardware capabilities and architecture, such as available memory and CPU cores, but the following should work in the majority of cases on x86_64-based hardware.

For UEFI boot to work, first copy both OVMF_CODE.secboot.fd and OVMF_VARS.ms.fd to a user-accessible location. In the following examples, we assume they’re in the local directory. On Ubuntu-based systems, the following commands will copy them to the local directory:

cp  /usr/share/OVMF/OVMF_CODE.secboot.fd .
cp /usr/share/OVMF/OVMF_VARS.ms.fd .

Without TPM emulation

To test Ubuntu Core without TPM emulation, omit the three lines that reference the TPM device:

qemu-system-x86_64 \
 -enable-kvm \
 -smp 1 \
 -m 2048 \
 -machine q35 \
 -cpu host \
 -global ICH9-LPC.disable_s3=1 \
 -net nic,model=virtio \
 -net user,hostfwd=tcp::8022-:22,hostfwd=tcp::8090-:80  \
 -drive file=OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,readonly=on \
 -drive file=OVMF/OVMF_VARS.ms.fd,if=pflash,format=raw,unit=1 \
 -drive "file=<ubuntu-core-image.img>",if=none,format=raw,id=disk1 \
 -device virtio-blk-pci,drive=disk1,bootindex=1 \
 -serial mon:stdio

With TPM emulation and full disk encryption

We recommend first installing a test snap that emulates TPM in software with libtpms (see the swtpm documentation for implementation details):

snap install --edge test-snapd-swtpm

The path to the snap’s libtpms-based socket (/var/snap/test-snapd-swtpm/current/swtpm-sock) is passed to the QEMU command:

sudo qemu-system-x86_64 \
 -enable-kvm \
 -smp 1 \
 -m 2048 \
 -machine q35 \
 -cpu host \
 -global ICH9-LPC.disable_s3=1 \
 -net nic,model=virtio \
 -net user,hostfwd=tcp::8022-:22,hostfwd=tcp::8090-:80  \
 -drive file=OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,readonly=on \
 -drive file=OVMF/OVMF_VARS.ms.fd,if=pflash,format=raw,unit=1 \
 -chardev socket,id=chrtpm,path="/var/snap/test-snapd-swtpm/current/swtpm-sock" \
 -tpmdev emulator,id=tpm0,chardev=chrtpm \
 -device tpm-tis,tpmdev=tpm0 \
 -drive "file=<ubuntu-core-image.img>",if=none,format=raw,id=disk1 \
 -device virtio-blk-pci,drive=disk1,bootindex=1 \
 -serial mon:stdio

Reset the TPM

If you wish to run a new clean image after previously running QEMU with the emulated TPM, you will need to reset the emulated TPM state. The safest way to do this is to purge remove and reinstall the emulator snap:

snap remove --purge test-snapd-swtpm
snap install --edge test-snapd-swtpm

Boot an ARM64 Ubuntu Core image

It is possible to boot Ubuntu Core arm64 images with qemu-system for arm64 on x86_64 systems. Additional requirements can be installed by running the following:

sudo apt install qemu-efi-aarch64 qemu-system-arm

To run the arm64 image without TPM, execute:

qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 2 -m 4096 \
                        -bios /usr/share/AAVMF/AAVMF_CODE.fd \
                        -netdev user,id=net0,hostfwd=tcp::8022-:22 \
                        -device virtio-net-pci,netdev=net0 \
                        -drive if=virtio,file="ucarm.img",format=raw \
                        -device virtio-gpu-pci \
                        -device virtio-keyboard \
                        -device virtio-mouse \
                        -serial mon:stdio

Due to QEMU emulating a different architecture, the full installation can take some time.

It is also possible to run with an emulated TPM by installing the same test-snapd-swtpm snap as for x86. For this to work, you need to first copy the UEFI variables from your system to the local directory. This only needs to be done once, before the first boot of a clean image:

cp /usr/share/AAVMF/AAVMF_VARS.ms.fd .

QEMU can now be run:

sudo qemu-system-aarch64 -machine virt -cpu cortex-a57 -smp 2 -m 4096 \
        -drive file=/usr/share/AAVMF/AAVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
        -drive file=AAVMF_VARS.ms.fd,if=pflash,format=raw,unit=1 \
        -netdev user,id=net0,hostfwd=tcp::8022-:22 \
        -device virtio-net-pci,netdev=net0 \
        -drive "file=uc.img",if=none,format=raw,id=disk1 \
        -device virtio-blk-pci,drive=disk1,bootindex=1 \
        -chardev socket,id=chrtpm,path=/var/snap/test-snapd-swtpm/current/swtpm-sock \
        -tpmdev emulator,id=tpm0,chardev=chrtpm \
        -device tpm-tis-device,tpmdev=tpm0 \
        -object rng-random,filename=/dev/urandom,id=rng0 \
        -device virtio-rng-pci,rng=rng0,id=rng-device0 \
        -device virtio-gpu-pci \
        -device virtio-keyboard \
        -device virtio-mouse \
        -serial mon:stdio

As before, due to QEMU emulating a different architecture the full installation can take some time.

Accessing the VM

In the the above QEMU commands, we forward the virtual SSH port 22 to port 8022 on the host. To access this configuration from your host machine, type the following:

ssh -i <path-to-private-key> <sso-username>@localhost -p 8022

In addition to SSH access, QEMU will start a VNC-shared console which can be accessed at vnc://localhost:5900 on the system. Some configurations may also forward port 80 to 8090 for any web server application you wish to install in the VM.

For a brief introduction on how to get started with Ubuntu Core, see Using Ubuntu Core.

4 Likes

“and 80 to 8090 for any web server application”

Sorry, I don’t see where that forwarding is being set, am I missing something?

You’re right - good catch! This was missed when I updated the QEMU invocation. I’ve added that part back in.

This page addresses using QEMU solely on x86_64 – is there any info on QEMU support for other platforms?

Not that I know of, but it’s something that would be very useful to have.

With https://github.com/snapcore/snapd/pull/11533 landed we moved to the slightly better named test-snapd-swtpm snap. The other one won’t go away but it would be best if this could get updated to use test-snapd-swtpm now instead of swtpm-mvo.

Thanks for the heads-up! The document has now been updated to use the new snap.

This is repeated a few lines below:

I tried to test UC 20 & 22 with QEMU. I have launched two images respectively on Ubuntu 22.04 LTS in a virtualbox VM. UC 22 has working fine, but UC 20 don’t execute the command snap refresh in the same host environment. The result is as follows on UC 20:

my-name@ubuntu:~$ snap refresh

error: cannot perform the following tasks:

- Download snap "snapd" (16292) from channel "latest/stable" (Get https://api.snapcraft.io/api/v1/snaps/download/PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4_16292.snap: EOF)

- Download snap "core20" (1623) from channel "latest/stable" (Get https://api.snapcraft.io/api/v1/snaps/download/DLqre5XGLbDqg9jPtiAhRRjDuPVa5X1q_1623.snap: EOF)

Does anyone know ?

Thanks for letting us know! I’ve fixed the duplication.

1 Like

Sorry for the delay replying to you. I’ve just tried this with the latest core20 image and it seems to be working - have you been able to try it again? It looks like the error you experienced might have been linked to the store being temporarily unavailable.

1 Like

Thanks for your replying. I have trid this with the latest core20 image with VPN and it works fine. Maybe our internet environment has a problem( :joy:). But if so, wo would try core20/22 in our product in china mainland market , does’t have a problem?

Glad it worked, and thanks for letting us know. Trying core20/22 in China shouldn’t be a problem - you might find Network requirements useful if you need more information on our domains and CDNs.

Thanks for your recommend.

1 Like

Just verified that references to “swtpm-mvo” snap should be replaced with “test-snapd-swtpm”, so you might want to globally search for that. Should still refer to edge channel.

Thanks - I’d not tried it recently, but it had stopped working. I’ve updated the doc and will give this a go when I test the x86 images.

Is there a page that actually explains the technology behind the TPM emulation?

No, but that’s a good point. I’ll add a link to https://github.com/stefanberger/swtpm/wiki, which I think will help.

I might consider adding a note that, when you “xz -d” to ucompress the compressed image, you lose the original compressed file, so you might want to add the “-k” option to keep it, and here’s why.

The instant you fire up that image under QEMU, it gets seeded and so on, so if you want to throw it away and start over, you want the original compressed image as your starting point all over again. It just saves time.

Great suggestion, thank you! I always annoyingly copy the archive manually.