Virtualization (KVM)

Virtualization (KVM)

Learning Objectives

Through this document, you will learn:

  • KVM/QEMU virtualization concepts and architecture
  • VM management using libvirt and virsh
  • Virtual network configuration
  • Snapshots and migration

Difficulty: Advanced


Table of Contents

  1. KVM/QEMU Overview
  2. Installation and Setup
  3. VM Creation
  4. virsh Commands
  5. Network Configuration
  6. Storage Management
  7. Snapshots and Migration

1. KVM/QEMU Overview

Virtualization Types

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Type 1 (Bare-metal)          Type 2 (Hosted)               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚  β”‚ VM β”‚ VM β”‚ VM   β”‚          β”‚ VM β”‚ VM β”‚ VM   β”‚          β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€          β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€          β”‚
β”‚  β”‚   Hypervisor    β”‚          β”‚   Hypervisor    β”‚          β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€          β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€          β”‚
β”‚  β”‚    Hardware     β”‚          β”‚   Host OS       β”‚          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€          β”‚
β”‚  ESXi, Xen, Hyper-V           β”‚    Hardware     β”‚          β”‚
β”‚                               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                               VirtualBox, VMware Workstationβ”‚
β”‚                                                             β”‚
β”‚  KVM - Linux kernel acts as Hypervisor (close to Type 1)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

KVM/QEMU Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       Virtual Machine                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Guest OS (Linux, Windows, etc.)                     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  QEMU: Device emulation (I/O, network, disk)               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  KVM kernel module: CPU/memory virtualization (HW support)  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Linux Kernel                                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Hardware (VT-x/AMD-V, VT-d)                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

libvirt Management Stack

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Management Tools                                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ virsh    β”‚  β”‚virt-managerβ”‚ β”‚Cockpit   β”‚  β”‚ API      β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜   β”‚
β”‚       β”‚             β”‚             β”‚             β”‚          β”‚
β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                           β”‚                                 β”‚
β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”                         β”‚
β”‚                    β”‚   libvirt   β”‚                         β”‚
β”‚                    β”‚ (libvirtd)  β”‚                         β”‚
β”‚                    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                         β”‚
β”‚                           β”‚                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚  β”‚            β”‚           β”‚           β”‚            β”‚       β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”   β”‚   β”Œβ”€β”€β”€β”€β”€β”β”‚   β”Œβ”€β”€β”€β”€β”€β”β”‚   β”Œβ”€β”€β”€β”€β”€β”  β”‚       β”‚
β”‚  β”‚  β”‚ KVM β”‚   β”‚   β”‚ QEMUβ”‚β”‚   β”‚ LXC β”‚β”‚   β”‚ Xen β”‚  β”‚       β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”˜   β”‚   β””β”€β”€β”€β”€β”€β”˜β”‚   β””β”€β”€β”€β”€β”€β”˜β”‚   β””β”€β”€β”€β”€β”€β”˜  β”‚       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Installation and Setup

Check Hardware Virtualization Support

# Check CPU virtualization support
grep -E '(vmx|svm)' /proc/cpuinfo

# vmx: Intel VT-x
# svm: AMD-V

# or
lscpu | grep Virtualization

# Check KVM module
lsmod | grep kvm

Package Installation

# Ubuntu/Debian
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients \
    bridge-utils virt-manager virtinst

# RHEL/CentOS
sudo yum install qemu-kvm libvirt libvirt-python \
    libguestfs-tools virt-install virt-manager

# Fedora
sudo dnf install @virtualization

Start Services

# Start libvirtd
sudo systemctl enable --now libvirtd

# Check status
sudo systemctl status libvirtd

# Add user to libvirt group (requires re-login)
sudo usermod -aG libvirt $USER
sudo usermod -aG kvm $USER

Verify Connection

# Test local connection
virsh -c qemu:///system list --all

# Or without sudo
virsh list --all

# System information
virsh nodeinfo

3. VM Creation

VM Creation with virt-install

# Basic VM creation
virt-install \
    --name ubuntu-vm \
    --ram 2048 \
    --vcpus 2 \
    --disk path=/var/lib/libvirt/images/ubuntu-vm.qcow2,size=20 \
    --os-variant ubuntu22.04 \
    --network bridge=virbr0 \
    --graphics vnc,listen=0.0.0.0 \
    --cdrom /path/to/ubuntu-22.04.iso \
    --boot cdrom,hd

Detailed Options

virt-install \
    --name centos-vm \
    --memory 4096 \
    --vcpus 4,maxvcpus=8 \
    --cpu host-passthrough \
    --disk path=/var/lib/libvirt/images/centos-vm.qcow2,size=40,format=qcow2,bus=virtio \
    --disk path=/var/lib/libvirt/images/centos-data.qcow2,size=100,format=qcow2 \
    --os-variant centos-stream9 \
    --network network=default,model=virtio \
    --graphics spice,listen=0.0.0.0 \
    --video qxl \
    --channel spicevmc \
    --location /path/to/CentOS-Stream-9.iso \
    --extra-args "console=ttyS0,115200n8 serial" \
    --initrd-inject /path/to/kickstart.cfg \
    --extra-args "ks=file:/kickstart.cfg" \
    --noautoconsole

Check OS Variant List

# List supported OS
osinfo-query os

# Search specific OS
osinfo-query os | grep -i ubuntu
osinfo-query os | grep -i centos

VM Creation with XML Definition

# VM definition XML example (/tmp/vm-definition.xml)
virsh define /tmp/vm-definition.xml

# Dump XML of existing VM
virsh dumpxml ubuntu-vm > ubuntu-vm.xml
<!-- vm-definition.xml example -->
<domain type='kvm'>
  <name>test-vm</name>
  <memory unit='GiB'>2</memory>
  <vcpu placement='static'>2</vcpu>
  <os>
    <type arch='x86_64' machine='pc-q35-6.2'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu mode='host-passthrough'/>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/test-vm.qcow2'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
    </interface>
    <graphics type='vnc' port='-1' autoport='yes'/>
    <console type='pty'/>
  </devices>
</domain>

4. virsh Commands

VM State Management

# VM list
virsh list             # Running VMs
virsh list --all       # All VMs
virsh list --inactive  # Stopped VMs

# Start/stop VM
virsh start vm-name
virsh shutdown vm-name     # Graceful shutdown
virsh destroy vm-name      # Force shutdown (power off)
virsh reboot vm-name

# Suspend/resume VM
virsh suspend vm-name
virsh resume vm-name

# Auto-start configuration
virsh autostart vm-name
virsh autostart --disable vm-name

VM Information Query

# Basic info
virsh dominfo vm-name

# Detailed configuration (XML)
virsh dumpxml vm-name

# CPU info
virsh vcpuinfo vm-name

# Memory info
virsh dommemstat vm-name

# Block device info
virsh domblklist vm-name
virsh domblkinfo vm-name vda

# Network interfaces
virsh domiflist vm-name
virsh domifstat vm-name vnet0

VM Console Access

# Serial console (requires guest configuration)
virsh console vm-name

# VNC/SPICE port check
virsh domdisplay vm-name
virsh vncdisplay vm-name

# Connect with virt-viewer
virt-viewer vm-name

VM Resource Changes

# Change CPU count (online)
virsh setvcpus vm-name 4 --live

# Change memory (online, requires pre-configuration)
virsh setmem vm-name 4G --live

# Set maximum (offline)
virsh setmaxmem vm-name 8G --config
virsh setvcpus vm-name 8 --maximum --config

# Edit XML directly
virsh edit vm-name

VM Deletion

# Delete VM definition (keep disk)
virsh undefine vm-name

# Delete VM and related storage
virsh undefine vm-name --remove-all-storage

# Delete including NVRAM (UEFI)
virsh undefine vm-name --nvram

5. Network Configuration

Default NAT Network

# Check default network
virsh net-list --all

# Start default network
virsh net-start default
virsh net-autostart default

# Network information
virsh net-info default
virsh net-dumpxml default

Bridge Network Setup

# Ubuntu: netplan configuration
# /etc/netplan/01-bridge.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
  bridges:
    br0:
      interfaces:
        - enp3s0
      dhcp4: yes
      parameters:
        stp: false
        forward-delay: 0
# Apply
sudo netplan apply
# RHEL/CentOS: NetworkManager
sudo nmcli connection add type bridge con-name br0 ifname br0
sudo nmcli connection add type ethernet con-name br0-slave-enp3s0 ifname enp3s0 master br0
sudo nmcli connection modify br0 ipv4.method auto
sudo nmcli connection up br0

libvirt Bridge Network Definition

<!-- /tmp/bridge-network.xml -->
<network>
  <name>host-bridge</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
</network>
# Create network
virsh net-define /tmp/bridge-network.xml
virsh net-start host-bridge
virsh net-autostart host-bridge

Isolated Network

<!-- /tmp/isolated-network.xml -->
<network>
  <name>isolated</name>
  <bridge name='virbr1'/>
  <ip address='192.168.100.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.100.10' end='192.168.100.254'/>
    </dhcp>
  </ip>
</network>

Adding Network Interface to VM

# Add interface (online)
virsh attach-interface vm-name network default --model virtio --live --config

# Remove interface
virsh detach-interface vm-name network --mac 52:54:00:xx:xx:xx --live --config

# List interfaces
virsh domiflist vm-name

6. Storage Management

Storage Pools

# Default pool (directory-based)
virsh pool-list --all

# Create pool (directory)
virsh pool-define-as mypool dir --target /var/lib/libvirt/images/mypool
virsh pool-build mypool
virsh pool-start mypool
virsh pool-autostart mypool

# LVM pool
virsh pool-define-as lvm-pool logical --source-name vg_vms --target /dev/vg_vms

# Pool information
virsh pool-info default

Volume Management

# List volumes
virsh vol-list default

# Create volume
virsh vol-create-as default disk1.qcow2 20G --format qcow2

# Volume information
virsh vol-info disk1.qcow2 --pool default
virsh vol-dumpxml disk1.qcow2 --pool default

# Delete volume
virsh vol-delete disk1.qcow2 --pool default

# Clone volume
virsh vol-clone disk1.qcow2 disk1-clone.qcow2 --pool default

# Resize volume
virsh vol-resize disk1.qcow2 30G --pool default

Disk Image Management (qemu-img)

# Create image
qemu-img create -f qcow2 disk.qcow2 20G

# Image information
qemu-img info disk.qcow2

# Convert image
qemu-img convert -f raw -O qcow2 disk.raw disk.qcow2
qemu-img convert -f vmdk -O qcow2 disk.vmdk disk.qcow2

# Resize image
qemu-img resize disk.qcow2 +10G

# Compress sparse image
qemu-img convert -O qcow2 -c disk.qcow2 disk-compressed.qcow2

Adding Disk to VM

# Add disk (online)
virsh attach-disk vm-name /var/lib/libvirt/images/extra.qcow2 vdb \
    --driver qemu --subdriver qcow2 --live --config

# Remove disk
virsh detach-disk vm-name vdb --live --config

# List block devices
virsh domblklist vm-name

7. Snapshots and Migration

Snapshot Management

# Create snapshot
virsh snapshot-create-as vm-name snap1 "First snapshot" --atomic

# Disk-only snapshot (no memory)
virsh snapshot-create-as vm-name snap-disk --disk-only --atomic

# List snapshots
virsh snapshot-list vm-name

# Snapshot information
virsh snapshot-info vm-name snap1

# Revert to snapshot
virsh snapshot-revert vm-name snap1

# Delete snapshot
virsh snapshot-delete vm-name snap1

# Check current snapshot
virsh snapshot-current vm-name

External Snapshots

# Create external snapshot (recommended for production)
virsh snapshot-create-as vm-name snap-external \
    --diskspec vda,snapshot=external \
    --disk-only --atomic

# Commit external snapshot (merge)
virsh blockcommit vm-name vda --active --pivot

# Block job information
virsh blockjob vm-name vda --info

Live Migration

# Target host preparation
# - Same libvirt version
# - Shared storage (NFS, GlusterFS, Ceph, etc.)
# - Network connectivity

# Execute migration
virsh migrate --live vm-name qemu+ssh://target-host/system

# With options
virsh migrate --live --persistent --undefinesource \
    --copy-storage-all \
    vm-name qemu+ssh://target-host/system

# Tunnelled migration (NAT environment)
virsh migrate --live --p2p --tunnelled \
    vm-name qemu+ssh://target-host/system

# Check migration status
virsh domjobinfo vm-name

Offline Migration

# Dump XML from source
virsh dumpxml vm-name > vm.xml

# Copy disk image
rsync -av /var/lib/libvirt/images/vm-disk.qcow2 target-host:/var/lib/libvirt/images/

# Define on target
virsh define vm.xml

# Delete from source
virsh undefine vm-name

Practice Problems

Problem 1: VM Creation

Create a VM with the following specifications using virt-install: - Name: test-server - Memory: 2GB - CPU: 2 - Disk: 20GB (qcow2) - Network: default (NAT) - Graphics: VNC

Problem 2: Network Configuration

Create an isolated internal network: - Name: internal - Subnet: 10.10.10.0/24 - DHCP: 10.10.10.100-200 - No NAT

Problem 3: Snapshot Management

  1. Create a snapshot of a VM
  2. Make changes to the VM (create a file, etc.)
  3. Revert to the snapshot
  4. Verify that changes were undone

Answers

Problem 1 Answer

virt-install \
    --name test-server \
    --memory 2048 \
    --vcpus 2 \
    --disk path=/var/lib/libvirt/images/test-server.qcow2,size=20,format=qcow2 \
    --os-variant generic \
    --network network=default \
    --graphics vnc,listen=0.0.0.0 \
    --cdrom /path/to/installer.iso \
    --boot cdrom,hd

Problem 2 Answer

<!-- /tmp/internal-net.xml -->
<network>
  <name>internal</name>
  <bridge name='virbr-int'/>
  <ip address='10.10.10.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.10.10.100' end='10.10.10.200'/>
    </dhcp>
  </ip>
</network>
virsh net-define /tmp/internal-net.xml
virsh net-start internal
virsh net-autostart internal

Problem 3 Answer

# 1. Create snapshot
virsh snapshot-create-as vm-name before-change "Before changes"

# 2. Make changes inside VM
virsh console vm-name
# (inside guest) touch /tmp/test-file

# 3. Revert to snapshot
virsh snapshot-revert vm-name before-change

# 4. Verify (file should not exist)
virsh console vm-name
# (inside guest) ls /tmp/test-file  # No such file

Next Steps


References

to navigate between lessons