Creating Fedora VMs with libvirt

Using libvirt and virt-install to create disposable Fedora Server VMs for testing.

When I need to debug a Linux-specific issue, I prefer testing it in a VM before touching my main install. The same applies when I want to check packages across distributions without polluting my host system.

This post uses Fedora Server 36 because I wanted a small target machine I could later provision with Ansible. The VM is intentionally boring: text install, serial console, enough disk and RAM to test packages.

For this, I usually reach for libvirt, an open-source tool for managing virtualization. It gives me virsh and virt-install, which are enough for the kind of disposable Linux VMs I need.

Installing libvirt on Fedora

On a Fedora host, install the virtualization group:

sudo dnf install @virtualization

That pulls in the pieces I care about here: virt-install, qemu-kvm, libvirt and the viewer tools:

Group: Virtualization
Description: These packages provide a graphical virtualization environment.
Mandatory Packages:
 virt-install
Default Packages:
 libvirt-daemon-config-network
 libvirt-daemon-kvm
 qemu-kvm
 virt-manager
 virt-viewer
Optional Packages:
 libguestfs-tools
 python3-libguestfs
 virt-top

After installation, start the libvirt service:

sudo systemctl start libvirtd

To enable the service at boot, run:

sudo systemctl enable libvirtd

Finally, verify that the KVM modules loaded:

[root@localhost ~]# lsmod | grep kvm
kvm_amd               114688  0
kvm                   831488  1 kvm_amd

Note

For more details on installing libvirt on Fedora, visit Getting started with virtualization. For a guide on how to install on Ubuntu, visit UbuntuKVMWalkthrough.

Creating the Dynamically Allocated Disk

Create a 20GB image for the VM:

sudo truncate --size=20480M /var/lib/libvirt/images/fedora36.img

I keep VM images under /var/lib/libvirt/images so they stay with the rest of libvirt’s storage.

Downloading Fedora 36 Server

Download Fedora Server from the official download page. This post used Fedora 36; if you want the same ISO, use this direct link. After downloading it, run virt-install:

sudo virt-install \
--name fedora36 \
--ram 4096 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/fedora36.img,size=20 \
--os-variant fedora36 \
--network bridge=virbr0 \
--graphics none \
--console pty,target_type=serial \
--location /tmp/Fedora-Server-dvd-x86_64-36-1.5.iso \
--extra-args 'console=ttyS0,115200n8'

Note

If you receive a permission error like this: ‘WARNING /path/to/fedora.iso may not be accessible by the hypervisor. You will need to grant the ‘qemu’ user search permissions for the following directories:’, place the Fedora ISO in a location that qemu has read permission for, in this case we’re placing the ISO in the /tmp folder.

The flags that matter most for this setup are --graphics none and --console pty,target_type=serial. They let me install and access the VM directly from the terminal instead of opening a graphical viewer.

Continuing the Installation

After running the command above, the following text will be displayed in your terminal:

Text mode provides a limited set of installation options. It does not offer
custom partitioning for full control over the disk layout. Would you like to use
VNC mode instead?

1) Start VNC
2) Use text mode

For this VM I use text mode. Answer with option 2 and press Enter.

If you chose text mode, configure the basics: timezone, root password, user, and any installation options you need. For a test VM, the default text installer flow is usually enough.

After finishing the text-mode configuration, press b to start the installation and wait.

Note

If at any point during installation you lose connection to the VM console, it’s possible to reconnect to the virtual machine by typing virsh console fedora36:

[root@localhost ~]# virsh console fedora36
Connected to domain fedora36
Escape character is ^]  # Enter key

The installation will be complete when the following message is displayed:

Installation complete. Press ENTER to quit:

Press Enter and the VM will restart.

Note

If the VM didn’t restart and just shut down, you can start it again by typing sudo virsh start fedora36:

[root@localhost ~]# sudo virsh start fedora36
Domain 'fedora36' started

After Installation

After reboot, connect to the guest again:

[root@localhost ~]# sudo virsh console fedora36
Connected to domain 'fedora36'
Escape character is ^] (Ctrl + ])

Press Enter and the guest will ask for a login. Use the account you configured during installation, or log in as root. At that point the VM is ready for package installs, tests, and isolated experiments.

virsh Commands I Keep Around

List all guests:

[root@localhost ~]# sudo virsh list --all
Id   Name       State
-----------------------------
7    fedora36   running
-    win11      shut off

Shut down a guest:

[root@localhost ~]# sudo virsh shutdown fedora36
Domain 'fedora36' is being shutdown

Reboot a guest:

[root@localhost ~]# sudo virsh reboot fedora36
Domain 'fedora36' is being rebooted

Display information about a guest:

[root@localhost ~]# sudo virsh dominfo fedora36
Id:             8
Name:           fedora36
OS Type:        hvm
State:          running
CPU(s):         2
CPU time:       27.5s
Max memory:     4194304 KiB
Used memory:    4194304 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: none
Security DOI:   0

For the complete list, use virsh --help:

[root@localhost ~]# sudo virsh --help
virsh [options]... [<command_string>]
virsh [options]... <command> [args...]

options:
  -c | --connect=URI      hypervisor connection URI
  -d | --debug=NUM        debug level [0-4]
  -e | --escape <char>    set escape sequence for console
  -h | --help             this help
  -k | --keepalive-interval=NUM
                          keepalive interval in seconds, 0 for disable
  -K | --keepalive-count=NUM
                          number of possible missed keepalive messages
  -l | --log=FILE         output logging to file
  -q | --quiet            quiet mode
  -r | --readonly         connect readonly
  -t | --timing           print timing information
  -v                      short version
  -V                      long version
       --version[=TYPE]   version, TYPE is short or long (default short)
commands (non interactive mode):
...
...
...
...

Once the VM is up, it becomes a safe target for provisioning tests. I use the same VM in the Ansible post to make the setup reproducible.

References

Comments

Back to top