Virtualization Concepts

Why This Matters

You are a sysadmin managing a rack of physical servers. Each server runs one application: a web server on one box, a database on another, a mail server on a third. Most of them sit at 5-10% CPU utilization all day, burning electricity, generating heat, and consuming rack space. When the web team needs a staging environment, they file a ticket and wait three weeks for new hardware to arrive.

Virtualization changed all of that. By running multiple virtual machines on a single physical host, organizations went from needing hundreds of physical servers to dozens. Provisioning dropped from weeks to minutes. Testing became trivial -- spin up a VM, break it, throw it away. Entire data centers shrank.

Today, virtualization is a foundational technology. Whether you are running KVM on a production hypervisor, QEMU for kernel development, or VirtualBox on your laptop for testing, understanding how virtualization works at the Linux level is essential. This chapter takes you from the concepts all the way to running your first virtual machine with open-source tools.


Try This Right Now

Check if your CPU supports hardware virtualization:

# On Intel CPUs, look for "vmx"; on AMD, look for "svm"
$ grep -E '(vmx|svm)' /proc/cpuinfo | head -1

You should see something like:

flags : ... vmx ...

If you see vmx or svm, your CPU supports hardware-assisted virtualization. If not, you may need to enable it in your BIOS/UEFI settings (look for "Intel VT-x" or "AMD-V").

Check if the KVM kernel module is loaded:

$ lsmod | grep kvm

Expected output (on Intel):

kvm_intel             368640  0
kvm                  1028096  1 kvm_intel
irqbypass              16384  1 kvm

If you see kvm_intel or kvm_amd, your system is ready for KVM virtualization.


What Is Virtualization?

At its core, virtualization is the act of creating a software-based (virtual) version of something -- a computer, an operating system, a storage device, or a network. The most common form is hardware virtualization, where you run multiple virtual machines (VMs) on a single physical host, each behaving as if it were its own independent computer.

┌─────────────────────────────────────────────────────────────┐
│                    Physical Hardware                         │
│              (CPU, RAM, Disk, Network)                       │
├─────────────────────────────────────────────────────────────┤
│                 Hypervisor / VMM                             │
│          (Manages and isolates VMs)                          │
├──────────────┬──────────────┬───────────────────────────────┤
│    VM 1      │    VM 2      │    VM 3                       │
│ ┌──────────┐ │ ┌──────────┐ │ ┌──────────┐                 │
│ │  App A   │ │ │  App B   │ │ │  App C   │                 │
│ ├──────────┤ │ ├──────────┤ │ ├──────────┤                 │
│ │  Libs    │ │ │  Libs    │ │ │  Libs    │                 │
│ ├──────────┤ │ ├──────────┤ │ ├──────────┤                 │
│ │ Guest OS │ │ │ Guest OS │ │ │ Guest OS │                 │
│ │ (Ubuntu) │ │ │ (CentOS) │ │ │ (Debian) │                 │
│ └──────────┘ │ └──────────┘ │ └──────────┘                 │
└──────────────┴──────────────┴───────────────────────────────┘

Each VM gets its own:

  • Virtual CPUs (vCPUs)
  • Virtual RAM
  • Virtual disk (a file on the host, typically)
  • Virtual network interface
  • Its own kernel, running its own operating system

The hypervisor (also called a Virtual Machine Monitor or VMM) is the software that creates and manages these virtual machines.


The Two Types of Hypervisors

Not all hypervisors are created equal. The industry classifies them into two types based on where they sit in the software stack.

Type 1: Bare-Metal Hypervisors

A Type 1 hypervisor runs directly on the physical hardware, with no host operating system underneath. The hypervisor is the operating system (or is deeply integrated into it).

┌───────────────────────────────────┐
│   VM 1    │   VM 2    │   VM 3   │
├───────────┴───────────┴──────────┤
│     Type 1 Hypervisor            │
│  (runs directly on hardware)     │
├──────────────────────────────────┤
│        Physical Hardware          │
└──────────────────────────────────┘

Open-source examples:

  • KVM (Kernel-based Virtual Machine) -- built into the Linux kernel itself
  • Xen -- used by AWS for years, powers many cloud providers

KVM is technically interesting because the Linux kernel becomes the hypervisor. When you load the KVM module, your Linux host becomes a Type 1 hypervisor that also happens to run a general-purpose operating system.

Type 2: Hosted Hypervisors

A Type 2 hypervisor runs as an application on top of a conventional operating system, just like any other program.

┌───────────────────────────────────┐
│   VM 1    │   VM 2    │   VM 3   │
├───────────┴───────────┴──────────┤
│    Type 2 Hypervisor             │
│   (runs as application)          │
├──────────────────────────────────┤
│     Host Operating System        │
│      (Linux, Windows, macOS)     │
├──────────────────────────────────┤
│       Physical Hardware           │
└──────────────────────────────────┘

Open-source examples:

  • QEMU (Quick EMUlator) -- can emulate entirely in software
  • VirtualBox -- popular desktop virtualization tool

Think About It: KVM is often called a Type 1 hypervisor even though it runs within Linux. Why? Because once the KVM module is loaded, the Linux kernel itself is the hypervisor -- it runs directly on hardware and manages VMs at the kernel level. The distinction between "bare metal" and "hosted" gets blurry with KVM, and that is actually one of its strengths.


Full Virtualization vs Paravirtualization

There are two fundamental approaches to virtualizing hardware.

Full Virtualization

In full virtualization, the guest operating system runs completely unmodified. It believes it is running on real hardware. The hypervisor traps privileged instructions from the guest and emulates them.

Pros:

  • Run any OS without modification (Windows, BSD, etc.)
  • Guests need zero awareness of virtualization

Cons:

  • Historically slower due to trap-and-emulate overhead
  • Hardware-assisted virtualization (VT-x/AMD-V) has largely eliminated the performance gap

KVM with hardware-assisted virtualization is full virtualization -- your guest OS does not need to know it is virtualized.

Paravirtualization

In paravirtualization, the guest OS is modified to be aware it is running in a virtual environment. Instead of executing privileged instructions that need to be trapped, the guest makes explicit "hypercalls" to the hypervisor.

Pros:

  • Can be faster for certain I/O-heavy operations
  • Efficient communication with the hypervisor

Cons:

  • Requires a modified guest kernel
  • Cannot run unmodified proprietary operating systems

Xen pioneered paravirtualization. Today, even full-virtualization setups use paravirtual drivers (like virtio in KVM) for disk and network I/O because they are faster than emulating real hardware.

Full Virtualization:                   Paravirtualization:

Guest OS (unmodified)                 Guest OS (modified)
    │                                     │
    │ privileged instruction              │ hypercall
    │                                     │
    ▼                                     ▼
Hypervisor traps & emulates          Hypervisor handles directly
    │                                     │
    ▼                                     ▼
  Hardware                             Hardware

KVM and QEMU: The Linux Virtualization Stack

KVM and QEMU are the two workhorses of Linux virtualization. They are separate projects that work together beautifully.

KVM (Kernel-based Virtual Machine)

KVM is a Linux kernel module that turns the kernel into a hypervisor. It leverages hardware virtualization extensions (Intel VT-x or AMD-V) to run guest code directly on the CPU at near-native speed.

What KVM handles:

  • CPU virtualization (using hardware VT-x/AMD-V)
  • Memory virtualization (using hardware EPT/NPT)
  • Interrupt handling

What KVM does not handle:

  • Device emulation (disks, network cards, displays)
  • VM management (creating, configuring VMs)

That is where QEMU comes in.

QEMU (Quick EMUlator)

QEMU is a user-space emulator that can emulate an entire computer system -- CPU, memory, devices, everything -- purely in software. It can run a guest OS for a completely different CPU architecture (e.g., run ARM code on x86).

When paired with KVM, QEMU delegates CPU and memory virtualization to KVM (which uses hardware acceleration) and handles everything else: disk controllers, network cards, USB devices, display output.

┌───────────────────────────────────────────┐
│            User Space                      │
│   ┌─────────────────────────────────┐     │
│   │          QEMU Process           │     │
│   │  ┌────────┐  ┌──────────────┐   │     │
│   │  │ Device │  │ VM Config    │   │     │
│   │  │ Emulat.│  │ & Management │   │     │
│   │  └────────┘  └──────────────┘   │     │
│   └──────────────┬──────────────────┘     │
│                  │ /dev/kvm               │
├──────────────────┼────────────────────────┤
│   Kernel Space   │                        │
│   ┌──────────────▼──────────────────┐     │
│   │          KVM Module             │     │
│   │  (CPU & Memory Virtualization)  │     │
│   └─────────────────────────────────┘     │
├───────────────────────────────────────────┤
│      Hardware (VT-x / AMD-V)              │
└───────────────────────────────────────────┘

Hands-On: Running a VM with QEMU/KVM

Let us install the tools and run a minimal VM.

Install on Debian/Ubuntu:

$ sudo apt update
$ sudo apt install -y qemu-system-x86 qemu-utils libvirt-daemon-system \
    libvirt-clients virtinst virt-manager

Install on Fedora/RHEL:

$ sudo dnf install -y qemu-kvm libvirt virt-install virt-manager

Distro Note: On Arch Linux, install qemu-full, libvirt, virt-manager, and dnsmasq. Then enable and start libvirtd.service.

Download a small test image (Alpine Linux, ~60MB):

$ mkdir -p ~/vms && cd ~/vms
$ wget https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-virt-3.19.1-x86_64.iso

Launch a VM directly with QEMU (without libvirt):

# Create a 2GB virtual disk
$ qemu-img create -f qcow2 alpine-test.qcow2 2G

# Boot the VM with KVM acceleration
$ qemu-system-x86_64 \
    -enable-kvm \
    -m 512 \
    -cpu host \
    -smp 2 \
    -drive file=alpine-test.qcow2,format=qcow2 \
    -cdrom alpine-virt-3.19.1-x86_64.iso \
    -boot d \
    -net nic -net user \
    -nographic

Let us break down those flags:

FlagMeaning
-enable-kvmUse KVM hardware acceleration
-m 512512 MB of RAM
-cpu hostPass through the host CPU model
-smp 22 virtual CPUs
-drive file=...,format=qcow2Virtual hard disk
-cdrom ...ISO image as virtual CD-ROM
-boot dBoot from CD-ROM first
-net nic -net userUser-mode networking (NAT)
-nographicConsole output in terminal

Press Ctrl+A then X to exit the QEMU console.


The libvirt Ecosystem

Running QEMU directly with command-line flags works, but it does not scale. Managing dozens of VMs with raw QEMU commands would be a nightmare. This is where libvirt comes in.

libvirt is a toolkit that provides a unified API for managing virtualization platforms. It supports KVM/QEMU, Xen, LXC, VirtualBox, and more. Think of it as an abstraction layer.

┌───────────────────────────────────────────┐
│           Management Tools                 │
│  ┌─────────┐ ┌──────────┐ ┌───────────┐  │
│  │  virsh   │ │virt-     │ │ Cockpit / │  │
│  │ (CLI)    │ │manager   │ │ oVirt     │  │
│  │         │ │(GUI)     │ │ (Web)     │  │
│  └────┬────┘ └────┬─────┘ └─────┬─────┘  │
│       └───────────┼──────────────┘        │
│                   ▼                        │
│           ┌───────────────┐               │
│           │   libvirtd    │               │
│           │   (daemon)    │               │
│           └───────┬───────┘               │
│                   │                        │
│       ┌───────────┼───────────┐           │
│       ▼           ▼           ▼           │
│   ┌───────┐  ┌────────┐  ┌────────┐      │
│   │ QEMU/ │  │  Xen   │  │  LXC   │      │
│   │  KVM  │  │        │  │        │      │
│   └───────┘  └────────┘  └────────┘      │
└───────────────────────────────────────────┘

Key components:

  • libvirtd -- the daemon that manages VMs
  • virsh -- the command-line interface
  • virt-manager -- a graphical desktop application
  • virt-install -- command-line tool for creating new VMs

Hands-On: Managing VMs with virsh

Start the libvirt daemon:

$ sudo systemctl enable --now libvirtd

List all VMs (called "domains" in libvirt terminology):

$ sudo virsh list --all
 Id   Name   State
-----------------------

Create a VM using virt-install:

$ sudo virt-install \
    --name alpine-test \
    --ram 512 \
    --vcpus 2 \
    --disk path=/var/lib/libvirt/images/alpine-test.qcow2,size=2 \
    --cdrom ~/vms/alpine-virt-3.19.1-x86_64.iso \
    --os-variant alpinelinux3.19 \
    --network network=default \
    --graphics none \
    --console pty,target_type=serial

Distro Note: If --os-variant alpinelinux3.19 is not recognized, run osinfo-query os | grep alpine to find valid values, or use --os-variant generic.

Common virsh commands:

# List running VMs
$ sudo virsh list

# Start a VM
$ sudo virsh start alpine-test

# Graceful shutdown
$ sudo virsh shutdown alpine-test

# Force power off (like pulling the plug)
$ sudo virsh destroy alpine-test

# Connect to VM console
$ sudo virsh console alpine-test

# View VM details
$ sudo virsh dominfo alpine-test

# View VM's XML configuration
$ sudo virsh dumpxml alpine-test

# Suspend (pause) a VM
$ sudo virsh suspend alpine-test

# Resume a paused VM
$ sudo virsh resume alpine-test

# Take a snapshot
$ sudo virsh snapshot-create-as alpine-test snap1 "First snapshot"

# List snapshots
$ sudo virsh snapshot-list alpine-test

# Revert to a snapshot
$ sudo virsh snapshot-revert alpine-test snap1

# Delete a VM (keeps disk by default)
$ sudo virsh undefine alpine-test

# Delete a VM and its disk
$ sudo virsh undefine alpine-test --remove-all-storage

Safety Warning: virsh destroy does NOT delete the VM. It force-powers it off (equivalent to pulling the power cord). virsh undefine --remove-all-storage permanently deletes the VM and its disk image.

virt-manager: The Graphical Interface

If you are on a desktop with X11/Wayland, virt-manager provides a full GUI for creating and managing VMs:

$ virt-manager

It connects to libvirtd and shows all your VMs. You can:

  • Create new VMs with a wizard
  • View VM consoles (graphical or serial)
  • Adjust CPU, memory, and disk settings
  • Manage virtual networks and storage pools
  • Take and manage snapshots

For headless servers, virt-manager can connect to remote libvirtd instances over SSH:

$ virt-manager --connect qemu+ssh://user@remote-host/system

Containers vs Virtual Machines

This is one of the most important architectural distinctions in modern infrastructure. Let us compare them clearly.

Virtual Machines:                    Containers:

┌──────────┐ ┌──────────┐          ┌──────────┐ ┌──────────┐
│  App A   │ │  App B   │          │  App A   │ │  App B   │
├──────────┤ ├──────────┤          ├──────────┤ ├──────────┤
│  Libs    │ │  Libs    │          │  Libs    │ │  Libs    │
├──────────┤ ├──────────┤          └────┬─────┘ └────┬─────┘
│ Guest OS │ │ Guest OS │               │            │
│ (kernel) │ │ (kernel) │          ─────┴────────────┴─────
└────┬─────┘ └────┬─────┘          │   Host OS Kernel     │
─────┴────────────┴─────           ├───────────────────────┤
│    Hypervisor        │           │      Hardware         │
├──────────────────────┤           └───────────────────────┘
│      Hardware        │
└──────────────────────┘
FeatureVirtual MachinesContainers
IsolationFull hardware-levelProcess-level (namespaces, cgroups)
KernelEach VM has its ownShares the host kernel
Boot timeSeconds to minutesMilliseconds to seconds
Resource overheadHundreds of MB per VMA few MB per container
Disk footprintGBs per VM imageMBs per container image
Security boundaryStrong (separate kernel)Weaker (shared kernel attack surface)
OS flexibilityRun any OS (Windows, BSD)Linux guests on Linux host only
DensityTens per hostHundreds to thousands per host
Use caseMulti-OS, strong isolationMicroservices, CI/CD, app packaging

When to Use VMs

  • You need to run different operating systems (Windows on a Linux host)
  • You require strong security isolation (multi-tenant environments)
  • You are running untrusted workloads
  • You need different kernel versions for different applications
  • Your application requires kernel modules not available on the host

When to Use Containers

  • You want fast startup times and high density
  • You are deploying microservices
  • You need consistent development/production environments
  • You want lightweight, portable packaging of applications
  • Your CI/CD pipeline needs to spin up environments rapidly

Think About It: Many production environments use both. VMs provide the security boundary between tenants, and containers run inside those VMs for application packaging. Cloud providers like AWS run your containers inside micro-VMs (Firecracker) for exactly this reason.


Debug This

A colleague complains their VM will not start. Here is the error:

$ sudo virsh start myvm
error: Failed to start domain 'myvm'
error: internal error: Cannot find suitable emulator for x86_64

What is wrong?

The QEMU binary is not installed or not in the expected path. libvirt cannot find qemu-system-x86_64.

Fix:

# Install QEMU
$ sudo apt install qemu-system-x86    # Debian/Ubuntu
$ sudo dnf install qemu-kvm           # Fedora/RHEL

# Verify it is installed
$ which qemu-system-x86_64
/usr/bin/qemu-system-x86_64

# Restart libvirtd
$ sudo systemctl restart libvirtd

# Try again
$ sudo virsh start myvm

Another common issue -- KVM acceleration not available:

$ sudo virsh start myvm
error: internal error: process exited while connecting to monitor:
Could not access KVM kernel module: No such file or directory

Fix: Load the KVM module:

$ sudo modprobe kvm_intel    # Intel CPUs
$ sudo modprobe kvm_amd      # AMD CPUs

# Verify
$ lsmod | grep kvm

If modprobe fails, check your BIOS settings -- hardware virtualization (VT-x or AMD-V) may be disabled.


Virtual Networking

libvirt sets up a default virtual network using a bridge called virbr0. VMs connect to this bridge and can reach the internet through NAT on the host.

# View virtual networks
$ sudo virsh net-list --all
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes
# View network details
$ sudo virsh net-info default
Name:           default
UUID:           a1b2c3d4-...
Active:         yes
Persistent:     yes
Autostart:      yes
Bridge:         virbr0
# Check the bridge on the host
$ ip addr show virbr0
5: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0

VMs on this network get IPs in the 192.168.122.0/24 range via DHCP served by dnsmasq (which libvirt manages automatically).


Virtual Disk Formats

QEMU supports several disk image formats:

FormatDescription
qcow2QEMU Copy-On-Write v2. Supports snapshots, compression, encryption. The standard choice.
rawNo overhead, slightly faster I/O, but no snapshots or compression.
vmdkVMware format. Useful for compatibility.
vdiVirtualBox format.

Working with qcow2 images:

# Create a 20GB thin-provisioned image (only uses space as data is written)
$ qemu-img create -f qcow2 disk.qcow2 20G

# Check image details
$ qemu-img info disk.qcow2

# Convert between formats
$ qemu-img convert -f raw -O qcow2 disk.raw disk.qcow2

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

What Just Happened?

┌─────────────────────────────────────────────────────────────┐
│                    CHAPTER RECAP                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Virtualization runs multiple OS instances on one machine.  │
│                                                             │
│  Type 1 hypervisors (KVM, Xen) run on bare metal.          │
│  Type 2 hypervisors (VirtualBox, QEMU) run as apps.        │
│                                                             │
│  KVM is a kernel module; QEMU handles device emulation.    │
│  Together they form the standard Linux virtualization       │
│  stack.                                                     │
│                                                             │
│  libvirt (virsh, virt-manager) provides unified VM          │
│  management across hypervisor backends.                     │
│                                                             │
│  Full virtualization = unmodified guest OS.                 │
│  Paravirtualization = modified guest with hypercalls.       │
│  virtio = paravirtual drivers for best I/O performance.    │
│                                                             │
│  VMs provide strong isolation with full kernels.            │
│  Containers are lightweight but share the host kernel.     │
│  Production environments often use both.                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Try This

  1. Basic VM creation: Install QEMU/KVM and libvirt on your system. Download the Alpine Linux ISO and create a VM using virt-install. Boot it, log in, and run uname -a inside the VM. How does the kernel differ from your host?

  2. Snapshot practice: Create a snapshot of your running VM. Make a change inside the VM (create a file, install a package). Revert to the snapshot and verify the change is gone.

  3. Explore virsh: Use virsh dominfo, virsh domstats, and virsh dumpxml to inspect your VM. Find out how much memory is allocated and how many vCPUs it has.

  4. Disk management: Create a second qcow2 disk image and attach it to your running VM using virsh attach-disk. Inside the VM, partition, format, and mount it.

  5. Bonus Challenge: Set up a second VM on the same virtual network. From VM 1, ping VM 2 by IP address. This demonstrates that libvirt's virtual network provides layer-2 connectivity between guests.