Skip to content

KVM/libvirt Virtualization

Before installing KVM, you must confirm that the CPU supports hardware virtualization (Intel VT-x or AMD-V).

Terminal window
# Check if the CPU supports virtualization extensions
grep -Ec '(vmx|svm)' /proc/cpuinfo

If the return value is greater than 0, the CPU supports virtualization.

Terminal window
# Check if KVM kernel modules are loaded
lsmod | grep kvm

You should see kvm and either kvm_intel (Intel CPU) or kvm_amd (AMD CPU).

Terminal window
sudo dnf install -y qemu-kvm libvirt virt-install virt-viewer \
libvirt-client bridge-utils

If you need a graphical management tool:

Terminal window
sudo dnf install -y virt-manager
Terminal window
sudo systemctl enable --now libvirtd

Verify:

Terminal window
sudo systemctl status libvirtd
virsh version
Terminal window
sudo usermod -aG libvirt $(whoami)

Log out and back in for the change to take effect. After that, you can use virsh as a regular user to connect to system-level VMs.

virsh is the command-line management tool for libvirt, used to manage the full lifecycle of virtual machines.

Terminal window
# List running VMs
virsh list
# List all VMs (including powered-off ones)
virsh list --all
# Start a VM
virsh start myvm
# Graceful shutdown
virsh shutdown myvm
# Force power off (equivalent to pulling the power plug)
virsh destroy myvm
# Reboot a VM
virsh reboot myvm
# Suspend/resume a VM
virsh suspend myvm
virsh resume myvm
Terminal window
# View VM details
virsh dominfo myvm
# View VM XML configuration
virsh dumpxml myvm
# View VM VNC display address
virsh vncdisplay myvm
# View disks used by a VM
virsh domblklist myvm
# View VM network interfaces
virsh domiflist myvm
Terminal window
# Edit VM XML configuration
virsh edit myvm
# Set VM to auto-start on boot
virsh autostart myvm
# Disable auto-start
virsh autostart --disable myvm
# Modify VM memory (requires powered-off state)
virsh setmaxmem myvm 4G --config
virsh setmem myvm 4G --config
# Modify vCPU count (requires powered-off state)
virsh setvcpus myvm 4 --config --maximum
virsh setvcpus myvm 4 --config
Terminal window
sudo virt-install \
--name almalinux9 \
--ram 2048 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/almalinux9.qcow2,size=20,format=qcow2 \
--os-variant almalinux9 \
--network network=default \
--graphics vnc,listen=0.0.0.0 \
--cdrom /data/iso/AlmaLinux-9-latest-x86_64-minimal.iso \
--boot uefi
Terminal window
sudo virt-install \
--name almalinux9-auto \
--ram 2048 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/alma9-auto.qcow2,size=20,format=qcow2 \
--os-variant almalinux9 \
--network network=default \
--graphics none \
--location /data/iso/AlmaLinux-9-latest-x86_64-minimal.iso \
--initrd-inject /data/ks/alma9-ks.cfg \
--extra-args "inst.ks=file:/alma9-ks.cfg console=ttyS0"
Terminal window
# Download the cloud image
wget https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2
# Copy and resize the disk
cp AlmaLinux-9-GenericCloud-latest.x86_64.qcow2 /var/lib/libvirt/images/myvm.qcow2
qemu-img resize /var/lib/libvirt/images/myvm.qcow2 20G
# Create a VM using cloud-init configuration
sudo virt-install \
--name myvm \
--ram 2048 \
--vcpus 2 \
--disk /var/lib/libvirt/images/myvm.qcow2 \
--os-variant almalinux9 \
--network network=default \
--import \
--cloud-init root-password-generate=on,disable=on \
--graphics none
Terminal window
# Create a snapshot
virsh snapshot-create-as myvm --name "before-update" --description "Before system update"
# List snapshots
virsh snapshot-list myvm
# Revert to a snapshot
virsh snapshot-revert myvm --snapshotname "before-update"
# Delete a snapshot
virsh snapshot-delete myvm --snapshotname "before-update"
Terminal window
# Create a new disk
qemu-img create -f qcow2 /var/lib/libvirt/images/data-disk.qcow2 50G
# Hot-add a disk to a VM
virsh attach-disk myvm /var/lib/libvirt/images/data-disk.qcow2 vdb \
--driver qemu --subdriver qcow2 --persistent
# View disk information
qemu-img info /var/lib/libvirt/images/myvm.qcow2
# Detach a disk
virsh detach-disk myvm vdb --persistent
Terminal window
# Power off the source VM first
virsh shutdown myvm
# Clone
virt-clone --original myvm --name myvm-clone \
--file /var/lib/libvirt/images/myvm-clone.qcow2
Terminal window
# Power off the VM
virsh destroy myvm
# Remove the VM definition
virsh undefine myvm
# Remove along with all storage
virsh undefine myvm --remove-all-storage

virt-manager provides a graphical interface for VM management.

Launch directly in a desktop environment:

Terminal window
virt-manager

Connect to a remote server’s libvirt from your local workstation:

Terminal window
virt-manager -c qemu+ssh://[email protected]/system

Or in the virt-manager interface, select “File > Add Connection”, choose QEMU/KVM, and check “Connect to remote host over SSH”.

libvirt creates a default NAT network named default (typically 192.168.122.0/24).

Terminal window
# List networks
virsh net-list --all
# View network details
virsh net-info default
# Start the default network
virsh net-start default
# Set the default network to auto-start
virsh net-autostart default

A bridged network allows VMs to connect directly to the physical network, obtaining IP addresses in the same subnet as the host.

  1. Create a bridge using nmcli:

    Terminal window
    # Create bridge br0
    sudo nmcli connection add type bridge con-name br0 ifname br0
    # Configure bridge IP (modify according to your network environment)
    sudo nmcli connection modify br0 \
    ipv4.addresses 192.168.1.100/24 \
    ipv4.gateway 192.168.1.1 \
    ipv4.dns "223.5.5.5,8.8.8.8" \
    ipv4.method manual
    # Add the physical NIC to the bridge
    sudo nmcli connection add type bridge-slave con-name br0-ens192 \
    ifname ens192 master br0
    # Activate the bridge (note: remote operation may disconnect the session)
    sudo nmcli connection up br0
    sudo nmcli connection down ens192
  2. Create a libvirt bridge network definition file /tmp/bridge-net.xml:

    <network>
    <name>host-bridge</name>
    <forward mode="bridge"/>
    <bridge name="br0"/>
    </network>
  3. Register the bridge network in libvirt:

    Terminal window
    virsh net-define /tmp/bridge-net.xml
    virsh net-start host-bridge
    virsh net-autostart host-bridge
  4. Use the bridged network when creating a VM:

    Terminal window
    sudo virt-install \
    --name bridged-vm \
    --ram 2048 \
    --vcpus 2 \
    --disk path=/var/lib/libvirt/images/bridged-vm.qcow2,size=20 \
    --os-variant almalinux9 \
    --network network=host-bridge \
    --cdrom /data/iso/AlmaLinux-9-latest-x86_64-minimal.iso
Terminal window
# Power off the VM
virsh shutdown myvm
# Edit the VM configuration
virsh edit myvm

In the XML, find the <interface> section and change it to:

<interface type='network'>
<source network='host-bridge'/>
<model type='virtio'/>
</interface>

Start the VM:

Terminal window
virsh start myvm
Terminal window
# Enable KSM (Kernel Same-page Merging) to save memory
sudo systemctl enable --now ksm
sudo systemctl enable --now ksmtuned
# Check KSM status
cat /sys/kernel/mm/ksm/pages_shared

VM configuration recommendations:

  • Use virtio drivers for the best disk and network performance
  • Prefer the qcow2 disk format (supports snapshots and thin provisioning)
  • Consider using raw format disks for I/O-intensive workloads
  • Allocate Hugepages for VMs to improve memory performance