The Kernel-based Virtual Machine (KVM) is a Linux hypervisor that supports full virtualization. When you install KVM on Linux, your Linux distribution is transformed into a Type-1 hypervisor (bare-metal), allowing you to run virtual machines at near-host machine speeds.
In this article, I’ll show you how to properly install KVM on Linux distributions such as Fedora, Rocky, Ubuntu, and Debian Linux.
Table of Contents
- 01. Overview of Key KVM Components
- 02. Check Virtualization Support
- 03. Install KVM on Linux Distributions
- 04. Install VirtIO Drivers for Windows Guests
- 05. Enable the Modular libvirt Daemon
- 06. Validate Host Virtualization Setup
- 07. Optimize the Host with TuneD
- 08. Configure a Network Bridge
- 09. Give the User System-Wide Permission
- 10. Set ACL on the Images Directory
- 11. Conclusion
01. Overview of Key KVM Components
Before you can install KVM on Linux, you must know the key components of KVM virtualization and what makes it run faster. Here is a quick overview.
KVM Kernel Modules
At the heart of KVM virtualization are its kernel modules. They consist of a loadable kernel module kvm.ko, which provides the core virtualization infrastructure, and a processor-specific kernel module kvm-intel.ko (Intel) or kvm-amd.ko (AMD).
The kernel modules will use the hardware-assisted virtualization capabilities of the CPU (Intel VT-x or AMD-Vi) to transform Linux into a Type-1 hypervisor. This allows you to run guest operating systems at speeds close to those of the host machine.
However, since the kernel modules have no interface, they provide all the resources needed to manage the virtualization to the user-space software.
QEMU
At the user-space level, it is managed by QEMU (Quick EMUlator). QEMU is a generic and open source machine emulator and virtualizer. It provides hardware emulation, like hard disks, network cards, VGA, PCI, etc., and a low-level interface to the virtual machine.
QEMU alone can emulate an entire machine, including a processor and various devices in the software, with no need for hardware-assisted virtualization. As an emulator, QEMU may thus target a broad range of computer architectures, from conventional x86-64 PCs to architectures such as ARM, MIPS, SPARC, and others. For example, on your host PC with an x86_64 board, you can run a virtual machine that can emulate the Raspberry Pi with a raspi3b board. Since this emulation happens entirely through software, it will be accurate but slow.
But when QEMU is paired with KVM, it’s a different story altogether. In the QEMU-KVM setup, QEMU focuses on emulating hardware devices while allowing the hypervisor (KVM kernel modules) to manage the CPU. With hypervisor support, QEMU may reach virtual machine CPU performance as near to that of the host computer.
Libvirt
Libvirt is a software suite that provides various tools to manage virtual machines and other virtualization functionality. These tools include an open-source API, a daemon, and a command-line utility (virsh
).
Some of the key capabilities of libvirt include virtual machine management, remote machine support, network and storage management, as well as virtual NAT and route-based network management.
Libvirt also provides a common means of managing multiple different virtualization platforms. Supported virtualization platforms include QEMU/KVM, Bhyve, Hyper-V, LXC, OpenVZ, PowerVM, UML, VMware ESXi and GSX, VMware Workstation, VirtualBox, and Xen.
XML Configuration File
Each virtual machine is associated with an XML configuration file (also called Domain XML) which defines all its settings.
When a virtual machine is started, the hypervisor uses this XML configuration file to create an instance of that virtual machine as a regular Linux user-space process on the host. This user-space process is scheduled by the standard Linux scheduler and can be managed by Linux utilities like top
and kill
.
These domain XML configuration files are located in the /etc/libvirt/qemu/ directory.
02. Check Virtualization Support
Check if your hardware supports KVM virtualization. If your hardware isn’t supported, you’ll get errors when trying to run a virtual machine.
Your processor must support hardware-assisted virtualization. It will be either Intel’s VT-x or AMD’s AMD-V.
$ lscpu | grep Virtualization
Virtualization: VT-x
I’m using an Intel processor. So I’m getting VT-x as output. If you have an AMD processor, the output should be AMD-V.
If the output is blank, the hardware virtualization extension is most likely disabled in the BIOS/UEFI. Before proceeding, enable it. It will be located in the CPU configuration section.
Next, ensure that your kernel includes KVM modules. The module is only available if set to y or m.
$ zgrep CONFIG_KVM /boot/config-$(uname -r)
CONFIG_KVM_GUEST=y
CONFIG_KVM_MMIO=y
CONFIG_KVM_ASYNC_PF=y
CONFIG_KVM_VFIO=y
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
CONFIG_KVM_COMPAT=y
CONFIG_KVM_XFER_TO_GUEST_WORK=y
CONFIG_KVM=m
CONFIG_KVM_INTEL=m
CONFIG_KVM_AMD=m
CONFIG_KVM_AMD_SEV=y
CONFIG_KVM_XEN=y
CONFIG_KVM_EXTERNAL_WRITE_TRACKING=y
If both steps are successful, proceed with the installation of KVM.
03. Install KVM on Linux Distributions
To use KVM virtualization on Linux, you’ll need 1) KVM kernel modules, 2) QEMU, and 3) the Libvirt software suite. Since Linux already includes KVM kernel modules, you just have to install QEMU and Libvirt to use the KVM hypervisor. However, there are a number of other virtualization management packages that are recommended when using virtualization.
Fedora / Rocky Linux
$ sudo dnf install qemu-kvm libvirt virt-install virt-manager virt-viewer \
edk2-ovmf swtpm qemu-img guestfs-tools libosinfo tuned
Ubuntu / Debian
$ sudo apt install qemu-kvm libvirt-daemon-system virtinst virt-manager \
virt-viewer ovmf swtpm qemu-utils libguestfs-tools libosinfo-bin tuned
A brief description of the packages listed above.
- qemu-kvm: A user-level KVM emulator that facilitates communication between hosts and VMs.
- libvirt/libvirt-daemon-system: A daemon that manages virtual machines and the hypervisor as well as handles library calls.
- virt-install/virtinst: A command-line tool for creating guest virtual machines.
- virt-manager: A graphical tool for creating and managing guest virtual machines.
- virt-viewer: A graphical console for connecting to a running virtual machine.
- qemu-img/qemu-utils: Provides tools to create, convert, modify, and snapshot offline disk images.
- guestfs-tools/libguestfs-tools: Provides a set of extended command-line tools for managing virtual machines.
- libosinfo/libosinfo-bin: A library for managing OS information for virtualization.
- tuned: A system tuning service for Linux.
04. Install VirtIO Drivers for Windows Guests
VirtIO drivers are para-virtualized drivers for KVM guests. Unfortunately, Microsoft does not provide VirtIO drivers. If you want to create a Microsoft Windows virtual machine, you need to download the virtio-win.iso image, which contains the VirtIO drivers for the Windows operating system.
Fedora / Rocky Linux
Install the VirtIO repository.
$ sudo wget https://fedorapeople.org/groups/virt/virtio-win/virtio-win.repo \
-O /etc/yum.repos.d/virtio-win.repo
By default, you can only install the stable version. If you want the most recent package, you must enable it in the repository. Open the /etc/yum.repos.d/virtio-win.repo file and change enabled=0 to enabled=1 under the section [virtio-win-latest].
$ sudo vim /etc/yum.repos.d/virtio-win.repo
...
[virtio-win-latest]
name=Latest virtio-win builds
baseurl=https://fedorapeople.org/groups/virt/virtio-win/repo/latest
enabled=1
skip_if_unavailable=1
gpgcheck=0
...
The virtio-win package can now be installed.
$ sudo dnf install virtio-win
The virtio-win.iso file will be saved in the /usr/share/virtio-win/ directory.
Ubuntu / Debian
For Ubuntu, Debian, or any other Linux distribution, you can directly download the latest version of virtio-win.iso.
$ wget https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso
When you create a Windows VM, you need to attach this ISO image to a CD-ROM. It includes all the VirtIO drivers necessary for Windows OS installation.
Check out this repository for a complete list of drivers, both old and new.
05. Enable the Modular libvirt Daemon
There are two types of libvirt daemons: monolithic and modular. The type of daemon(s) you use affects how granularly you can configure individual virtualization drivers.
The traditional monolithic libvirt daemon, libvirtd, manages a wide range of virtualization drivers via centralized hypervisor configuration. However, this may result in inefficient use of system resources.
In contrast, the newly introduced modular libvirt provides a specific daemon for each virtualization driver. As a result, modular libvirt daemons offer more flexibility in fine-tuning libvirt resource management.
While most Linux distributions have started to offer a modular option, at the time of writing, Debian and Ubuntu continue to offer only a monolithic daemon.
Fedora / Rocky Linux
$ for drv in qemu interface network nodedev nwfilter secret storage; do \
sudo systemctl enable virt${drv}d.service; \
sudo systemctl enable virt${drv}d{,-ro,-admin}.socket; \
done
Ubuntu / Debian
$ sudo systemctl enable libvirtd.service
A reboot is recommended so that the KVM can properly start.
$ sudo reboot
06. Validate Host Virtualization Setup
After the reboot, verify that your host is correctly configured to run all libvirt hypervisor drivers.
$ sudo virt-host-validate qemu
You may receive the following warning message from the validation tool:
QEMU: Checking for device assignment IOMMU support : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
Meaning: Your Intel processor only supports the VT-x (vmx) feature and not VT-d.
---
QEMU: Checking if IOMMU is enabled by kernel : WARN (IOMMU appears to be disabled in kernel. Add intel_iommu=on to kernel cmdline arguments)
Meaning: Your Intel CPU supports the VT-d capability, but it must be enabled in the kernel.
#### For Intel CPU
$ sudo vim /etc/default/grub
...
GRUB_CMDLINE_LINUX="... intel_iommu=on iommu=pt"
...
If you have an AMD CPU, IOMMU is enabled by default. To enable pass-through mode, just add iommu=pt.
#### For AMD CPU
$ sudo vim /etc/default/grub
...
GRUB_CMDLINE_LINUX="... iommu=pt"
...
Then, regenerate the grub configuration file.
Fedora / Rocky Linux
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
Ubuntu / Debian
$ sudo update-grub
Reboot the system and validate the host again to ensure that no issues remain.
$ sudo virt-host-validate qemu
On the Intel CPU, verify that the VT-d is enabled.
$ dmesg | grep -i -e DMAR -e IOMMU
On the AMD CPU, verify that the AMD-Vi is enabled.
$ dmesg | grep -i -e AMD-Vi
---
QEMU: Checking for secure guest support : WARN (Unknown if this platform has Secure Guest support)
Meaning: If you have an Intel CPU, you can safely ignore this warning. This applies to AMD CPUs. If you have an AMD CPU, please see the ‘Red Hat Bugzilla 1850351‘ link to resolve this issue.
07. Optimize the Host with TuneD
TuneD is a system tuning service for Linux. It provides a number of pre-configured tuning profiles, each optimized for unique workload characteristics, including CPU-intensive job needs, storage/network throughput responsiveness, or power consumption reduction.
Enable and start the TuneD service.
$ sudo systemctl enable --now tuned
Find out which TuneD profile is currently active.
$ tuned-adm active
Current active profile: balanced
List all TuneD profiles that are available on your system
$ tuned-adm list
Available profiles:
- accelerator-performance - Throughput performance based tuning with disabled higher latency STOP states
- aws - Optimize for aws ec2 instances
- balanced - General non-specialized tuned profile
- desktop - Optimize for the desktop use-case
- hpc-compute - Optimize for HPC compute workloads
- intel-sst - Configure for Intel Speed Select Base Frequency
- latency-performance - Optimize for deterministic performance at the cost of increased power consumption
- network-latency - Optimize for deterministic performance at the cost of increased power consumption, focused on low latency network performance
- network-throughput - Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks
- optimize-serial-console - Optimize for serial console use.
- powersave - Optimize for low power consumption
- throughput-performance - Broadly applicable tuning that provides excellent performance across a variety of common server workloads
- virtual-guest - Optimize for running inside a virtual guest
- virtual-host - Optimize for running KVM guests
Current active profile: balanced
I will set the profile to virtual-host. This optimizes the host for running KVM guests.
$ sudo tuned-adm profile virtual-host
Check that the TuneD profile has been updated and that virtual-host is now active.
$ tuned-adm active
Current active profile: virtual-host
Make sure there are no errors.
$ sudo tuned-adm verify
Verfication succeeded, current system settings match the preset profile.
See TuneD log file ('/var/log/tuned/tuned.log') for details.
Your host is now optimized to run KVM guests. When you create a Linux virtual machine, you can also enable TuneD and set the TuneD profile to virtual-guest to improve virtual guest performance.
To learn more about the tuned-adm
command, go to its GitHub page.
08. Configure a Network Bridge
All the virtual machines on the host are by default connected to the same NAT-type virtual network, named ‘default‘.
$ sudo virsh net-list --all
Name State Autostart Persistent
--------------------------------------------
default active yes yes
Note: If you use Debian, the default network state will be inactive, and autostart will be disabled. To activate, run the command
sudo virsh net-start default
followed bysudo virsh net-autostart default
.
The virtual machines that use this ‘default’ network will be assigned an IP address in the 192.168.122.0/24 address space, with the host OS reachable at 192.168.122.1.
$ sudo virsh net-dumpxml default | xmllint --xpath '//ip' -
<ip address="192.168.122.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.122.2" end="192.168.122.254"/>
</dhcp>
</ip>
Virtual machines using this default network will only have outbound network access. Virtual machines will have full access to network services, but devices outside the host will be unable to communicate with virtual machines inside the host. For example, the virtual machine can browse the web but cannot host a web server that is accessible to the outside world.
If you want virtual machines to be directly visible on the same physical network as the host and visible to external devices, you must use a network bridge.
A network bridge is a link-layer device that connects two local area networks into one network. In this case, a software bridge is used within a Linux host to simulate a hardware bridge. As a result, all other physical machines on the same physical network of the host can detect and access virtual machines. The virtual machine, for example, can browse the web, and will also be able to host a web server that is accessible to the outside world.
First, find the name of the interface you want to add to the bridge. In my case, it is enp3s0.
$ sudo nmcli device status
DEVICE TYPE STATE CONNECTION
enp3s0 ethernet connected Wired connection 1
virbr0 bridge connected (externally) virbr0
lo loopback unmanaged --
Create a bridge interface. I’ll name it bridge0, but you can call it whatever you want.
$ sudo nmcli connection add type bridge con-name bridge0 ifname bridge0
Assign the interface to the bridge. I’m going to name this connection ‘Bridge connection 1‘, but you can call it whatever you want.
$ sudo nmcli connection add type ethernet slave-type bridge \
con-name 'Bridge connection 1' ifname enp3s0 master bridge0
The following step is optional. If you want to configure a static IP address, use the following commands; otherwise, skip this step. Change the IP address and other details to match your configuration.
$ sudo nmcli connection modify bridge0 ipv4.addresses '192.168.1.7/24'
$ sudo nmcli connection modify bridge0 ipv4.gateway '192.168.1.1'
$ sudo nmcli connection modify bridge0 ipv4.dns '8.8.8.8,8.8.4.4'
$ sudo nmcli connection modify bridge0 ipv4.dns-search 'sysguides.com'
$ sudo nmcli connection modify bridge0 ipv4.method manual
Activate the connection.
$ sudo nmcli connection up bridge0
Enable the connection.autoconnect-slaves parameter of the bridge connection.
$ sudo nmcli connection modify bridge0 connection.autoconnect-slaves 1
Reactivate the bridge.
$ sudo nmcli connection up bridge0
Verify the connection. If you get your IP address from DHCP, it may take a few seconds to lease a new one. So please be patient.
$ sudo nmcli device status
DEVICE TYPE STATE CONNECTION
bridge0 bridge connected bridge0
virbr0 bridge connected (externally) virbr0
enp3s0 ethernet connected Bridge connection 1
lo loopback unmanaged --
$ ip -brief addr show dev bridge0
bridge0 UP 192.168.1.7/24 fe80::4644:919a:fb2d:35a1/64
You can now start using a network bridge when creating virtual machines.
However, it is recommended that you also set up a virtual bridge network in KVM so that the virtual machines can use this bridge interface by name.
Create an XML file called nwbridge.xml and fill it with the following information. I’ll call my host network bridge nwbridge, but you can call it whatever you want.
$ vim nwbridge.xml
<network>
<name>nwbridge</name>
<forward mode='bridge'/>
<bridge name='bridge0'/>
</network>
Define nwbridge as a persistent virtual network.
$ sudo virsh net-define nwbridge.xml
Activate the nwbridge and set it to autostart on boot.
$ sudo virsh net-start nwbridge
$ sudo virsh net-autostart nwbridge
Now you can safely delete the nwbridge.xml file. It’s not required anymore.
$ rm nwbridge.xml
Finally, verify that the virtual network bridge nwbridge is up and running.
$ sudo virsh net-list --all
Name State Autostart Persistent
---------------------------------------------
default active yes yes
nwbridge active yes yes
A network bridge has been created. You can now start using the nwbridge network bridge in your virtual machines. The virtual machines will get their IP addresses from the same pool as your host machine.
If you ever want to remove this network bridge and return it to its previous state, then run the following commands.
$ sudo virsh net-destroy nwbridge
$ sudo virsh net-undefine nwbridge
$ sudo nmcli connection up 'Wired connection 1'
$ sudo nmcli connection down bridge0
$ sudo nmcli connection del bridge0
$ sudo nmcli connection del 'Bridge connection 1'
09. Give the User System-Wide Permission
Libvirt provides two methods for connecting to the local qemu-kvm hypervisor.
qemu:///session
Connect as a regular user to a per-user instance locally. This is the default mode when running a virtual machine as a regular user. This allows users to only manage their own virtual machines.
$ virsh uri
qemu:///session
qemu:///system
Connect to a system instance as the root user locally. When run as root, it has complete access to all host resources. This is also the recommended method to connect to the local hypervisor.
$ sudo virsh uri
qemu:///system
So, if you want to connect to a system instance as a regular user with full access to all host resources, do the following.
Note: For Ubuntu users, system-wide permissions are enabled by default. You can skip this section and move on to the next.
Add the regular user to the libvirt group.
$ sudo usermod -aG libvirt $USER
Define the environment variable LIBVIRT_DEFAULT_URI in the local .bashrc file of the user.
$ echo "export LIBVIRT_DEFAULT_URI='qemu:///system'" >> ~/.bashrc
$ source ~/.bashrc
Check again as a regular user to see which instance you are connected to.
$ virsh uri
qemu:///system
You can now use the virsh
command-line tool and the Virtual Machine Manager (virt-manager
) without sudo
.
10. Set ACL on the Images Directory
By default, virtual machine disk images are stored in the /var/lib/libvirt/images directory. Only the root user has access to this directory.
$ ls /var/lib/libvirt/images/
ls: cannot open directory '/var/lib/libvirt/images/': Permission denied
As a regular user, you might want access to this directory without having to type sudo
every time. So, setting the ACL for this directory is the best way to access it without changing the default permissions.
First, recursively remove any existing ACL permissions on the directory.
$ sudo setfacl -R -b /var/lib/libvirt/images
Grant regular user permission to the directory recursively.
$ sudo setfacl -R -m u:$USER:rwX /var/lib/libvirt/images
The capital ‘X’ above indicates that ‘execute’ should only be applied to child folders and not child files.
All existing directories and files (if any) in /var/lib/libvirt/images/ now have permissions. However, any new directories and files created within this directory will not have any special permissions. To get around this, we need to enable ‘default’ special permissions. The ‘default acls’ can only be applied to directories and not to files.
$ sudo setfacl -m d:u:$USER:rwx /var/lib/libvirt/images
Now review your new ACL permissions on the directory.
$ getfacl /var/lib/libvirt/images
getfacl: Removing leading '/' from absolute path names
# file: var/lib/libvirt/images
# owner: root
# group: root
user::rwx
user:madhu:rwx
group::--x
mask::rwx
other::--x
default:user::rwx
default:user:madhu:rwx
default:group::--x
default:mask::rwx
default:other::--x
Try accessing the /var/lib/libvirt/images directory again as a regular user.
$ touch /var/lib/libvirt/images/test_file
$ ls -l /var/lib/libvirt/images/
total 0
-rw-rw----+ 1 madhu madhu 0 Feb 12 21:34 test_file
You now have full access to the /var/lib/libvirt/images directory.
11. Conclusion
In this blog, you have learned about key elements of KVM virtualization and how they relate to each other. You have also learned how to install KVM on a variety of Linux distributions.
You should be able to start creating virtual machines right away. If you would like to install a virtual machine using the command line, visit my blog “How to Install a KVM Guest OS from the Command-Line“. But if you want to install a virtual machine using a Virtual Machine Manager, check out my other blog, “How to Install Guest OS in Virt-Manager: A Quick Intro“.