Basics of Virtualization in Linux

The goal of this article is to explore some basic terminology and concepts around virtualization in Linux systems. It’s mostly intended as a quick reference, rather than a deep dive. I have decided to write this article, as I’ve previously touched on connecting to VMs, without talking about virtualization itself.

Hypervisor

A hypervisor is a piece of software that is responsible for creating and running virtual machines. The system on which the hypervisor runs virtual machines is called the host system, and the virtual machines themselves are called guest systems. The hypervisor manages and provides resources to the guest OS.

There are two main categories of hypervisors:

Type 1 Hypervisor

These run on bare metal and typically make use of the CPU’s feature set specifically built for virtualization, like AMD-V and Intel VT-x. This feature set is usually something that can be toggled in the BIOS to enable/disable. In this article the focus will be on kvm based virtualization. But there are other type 1 hypervisors, like VMWare ESXi and MS Hyper-V.

Type 2 Hypervisor

These run on top of a host OS, so they must negotiate with the host OS for system resources adding some overhead. This type includes solutions like qemu, VMWare Workstation and VirtualBox.

Type 1 vs Type 2

kvm/qemu

On its own, qemu can emulate systems entirely in software, including systems that use a different CPU architecture than the host, and kvm is a kernel module that can provide the efficiency of a type-1 hypervisor, kvm and qemu are able to interact each other, if:

In this fashion, qemu can delegate CPU execution and the memory virtualization to kvm, therefore making that part of the virtualization process type 1. Other things, such as calls to IO devices and disk drives, are routed through the OS, in a different fashion. In this way, the two can work together where qemu can build and manage virtual hardware components, and pass CPU and memory heavy instructions for processing to kvm, resulting in something between types 1 and 2.

The main takeaway is that kvm is a linux kernel subsystem that exposes hardware virtualization capabilities, while qemu provides the virtual hardware and machine emulation.

To check whether your CPU supports virtualization, use the following command:

root@linuxpc:/etc# kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

The output will be fairly self-explanatory here.

If the above command is not found, then you can query device info manually:

grep -Ec '(vmx|svm)' /proc/cpuinfo

If the value is greater than 0, the CPU can support virtualization.

libvirt

Libvirt provides an interface that helps abstract away differences between different hypervisors, so that they can all be operated with a single toolset.

It gives:

We will need this in order to be able to actually install and manage VMs, without having to directly call qemu binaries with long argument strings.

To install, as root:

apt install libvirt-daemon-system virtinst

Since we are talking about kvm/qemu here, we’ll also want to actually install qemu:

apt install qemu

Spinning up a VM

First, a disk image file is needed, which the VM can use as its disk. The format can be raw or qcow2.

qemu-img create -f raw -o size=30G vm1.raw

This should create an image with a 30G disk. It can be extended later if it’s not big enough.

Once the disk image is created, the disk image can be used as storage for spinning up a VM, using virt-install, passing an installation media so that some OS can be installed, in my case debian, but you can use whatever you like.

virt-install --name=vm1 --ram=8192 --vcpus=2 --disk path=vm1.raw --cdrom=/home/conquistador/Downloads/debian-12.11.0-amd64-netinst.iso --os-variant debian12.11.0 --network bridge=virbr-wifi,model=virtio

The flags are mostly self explanatory but let’s go through them anyway:

If you don’t know the os-variant, you can give --osinfo detect=on,require=off a shot.

When executed, a virt-viewer window should appear with the installer running, and it should proceed as normal. The virt-viewer can be ran anytime to view the VM, e.g.

virt-viewer vm1

If you do use virt-viewer, you’ll want to use & and disown so you don’t have to keep the terminal window open.

Commands to shut down, start, and reboot it:

virsh shutdown vm1
virsh start vm1
virsh reboot vm1

Interactive TUI installations are also possible, then you need slightly different parameters, and the steps will be printed to the terminal. Furthermore, entirely headless installations are also supported. (Not covered here)

Machines can be told to autostart (or stop autostarting) along with whenever libvirtd comes up/stops:

virsh autostart vm1
virsh autostart --disable vm1

Sidenote on a fresh install of kvm/qemu

If the kvm/qemu is a fresh installation, there may not be networking access definitions out of the box, in that case, may need to create and apply a default one. E.g. create a file /tmp/default.xml:

<network>
  <name>default</name>
  <bridge name='virbr0'/>
  <forward/>
  <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>
</network>

Then tell libvirt to read this definition:

virsh net-define /tmp/default.xml

Don’t worry about the /tmp location, libvirt should save a definition for itself, but if you don’t trust it, go ahead and replace the path with /usr/share/libvirt/networks.

And start up the new network interface:

virsh net-start default
virsh net-autostart default

Sidenote on disk images

When it comes to disk image formats, the two options are raw vs qcow2.

There are two main things to keep in mind:

If you care about the overall state of the VM, qcow2 is better, if you are like me and prefer to use ZFS to snapshot working data on the storage layer, raw is good enough.

Sidenote on virtio

virtio is a paravirtualized device standard designed specifically for virtual machines.

Instead of emulating a piece of physical hardware such as a real network card or disk controller, it allows the guest OS to communicate more directly with the hypervisor, reducing overhead.

Troubleshooting

Disk with installed VM exists, VM not registered

If the disk exists, but vm not defined, just call virt-install on the disk without plugging a cdrom installer:

virt-install --name=vm1 --ram=8192 --vcpus=2 --disk path=vm1.raw --osinfo detect=on,require=off --network bridge=virbr-wifi,model=virtio --import

The --import flag is what does the magic here: it tells virt-install that we want to build the VM around an existing disk image, rather than install.

VM running low on space

Extend the space on the VM disk in the host machine:

qemu-img resize vol.raw +5G

Inside the guest/ext4:

# grow the partition, extending the partition container to the end of the disk
growpart /dev/sda1

Then, expand the filesystem later to fill the newly grown partition

resize2fs /dev/sda1

Definitely make a backup of any useful or important data on the VM before doing this.

Cloning a VM

This is fairly straight forward, as long as you have enough space on the host:

virt-clone --original source_vm_name --name cloned_vm_name --auto-clone

Make sure you don’t forget to change hostname and assign a different IP for the cloned VM.