← Back to Course Index

Lab Icon Week 2 - Lab 1: KVM Virtualization Fundamentals

Module: Operating Systems 3 (Virtualisation & Cloud Technologies) Instructor: KT Nshimba Topic: KVM CLI, QEMU, and Low-Level Virtualization Estimated Time: 45 Minutes


Lab Overview

In this lab, you will interact with the "Engine" (KVM/QEMU) directly to understand the low-level mechanics of virtualization. This "under-the-hood" looking is essential before using high-level interfaces like Proxmox VE.

Objectives:

  1. Part A: Verify hardware virtualization support and prepare virtual disks.
  2. Part B: Launch a Virtual Machine via CLI, log in, and manage its power state.
  3. Part C: (Bonus) Permanently install Alpine Linux to the virtual disk.
  4. Part D: Use libvirt and virsh to accomplish the same tasks through a management API.

Prerequisites:


Part A: Verification & Preparation

Before we can run a VM, we must ensure the host is ready and we have storage.

  1. Verify CPU Support

Check if your processor supports hardware virtualization (VT-x or AMD-V).

lscpu | grep Virtualization

2. Verify Kernel Modules

Ensure the Linux Kernel has the KVM hypervisor modules loaded.

lsmod | grep kvm

3. Verify Permissions

Ensure your user can access the /dev/kvm device node.

ls -l /dev/kvm

4. Virtual Disk Configuration

We will now prepare the storage for our Virtual Machine. In this step, we will create the disk image and briefly explore how different formats (QCOW2 vs RAW) behave on the filesystem.

Step 1: Create the Disk Use qemu-img to create a qcow2 (QEMU Copy On Write) disk. This format is "Thinly Provisioned", meaning it only uses space as data is written.

qemu-img create -f qcow2 test-disk.qcow2 10G

Step 2: Format Analysis (Concepts) Virtual disks come in many formats. Let's verify why we chose QCOW2 by converting it to RAW and comparing the size. 1. Convert Qcow2 to Raw: bash qemu-img convert -f qcow2 -O raw test-disk.qcow2 test-disk.img 2. Compare Sizes: Run ls -lh test-disk.*

**Comparison Table**:
| File | Format | Actual Size on Disk (ls -lh) | Explanation |
| :--- | :--- | :--- | :--- |
| test-disk.qcow2 | QCOW2 | ____________________ | Grows on demand (Thin) |
| test-disk.img | RAW | ____________________ | Pre-allocated (Thick) |

6. Part A Summary: Deployment Readiness

Before proceeding to Part B (launching the VM), confirm you have the following pieces in place. Missing any one of these will cause the launch command to fail.

Deployment Checklist:

Critical Thinking:


Part B: Launching & Logging In

Now we will manually perform the job of a hypervisor management tool. We will download a minimal Operating System, wire up the virtual hardware using QEMU commands, and boot the machine.

1. Download Boot Image (Alpine Linux)

We use Alpine Linux because it is tiny (~60MB) and boots instantly.

wget https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/x86_64/alpine-virt-3.20.0-x86_64.iso

2. The Launch Command

Execute the following single command to build and boot the VM.

Tip: If you are using a server without a GUI, add -nographic to the end.

qemu-system-x86_64 \
  -enable-kvm \
  -m 512 \
  -drive file=test-disk.qcow2,format=qcow2 \
  -cdrom alpine-virt-3.20.0-x86_64.iso \
  -boot d

Command Analysis:

3. Log In to the VM (Live Session)

Note: We are booting into a Live RAM Environment directly from the ISO. You do not need to install the OS to log in. The test-disk.qcow2 we attached is present but currently empty.

  1. The VM will boot and scroll text.
  2. At the prompt localhost login:, type:

    • User: root
    • Password: (None, just press Enter)
    • You are now inside the VM! Run uname -a to see the guest kernel.

4. Verify Virtual Hardware

Even though we didn't install to the disk, let's prove it is connected. 1. Check Disks: bash fdisk -l 2. Record:

*   **Device Name**: ____________________ (Likely `/dev/vda`)
*   **Size**: ____________________ (Should be 10 GiB)
*   **Conclusion**: The disk we created in Part A is successfully "wired" to the VM.

5. Basic Networking Test

By default, QEMU uses SLIRP (User Networking), which acts like a NAT behind the host process. 1. Check IP: bash ip addr show

*   **Record IP**: ____________________ (e.g., 10.0.2.15)
  1. Test Connectivity: bash ping -c 3 8.8.8.8

    • Result: Did it reply? [ ] Yes [ ] No

Critical Thinking:

6. Shutdown

To turn off the VM safely:

poweroff

The QEMU window should close (or the process terminate).


Part C: Bonus Challenge - Permanent Installation

For students who want to go further, you can install the OS permanently to the test-disk.qcow2 file. This means your changes will be saved even after you shutdown.

1. Run the Installer

Start the VM again (using the command from Part B) if it is off. Inside the VM, run the Alpine setup script:

setup-alpine

2. Verify Persistence

  1. Shutdown the VM (poweroff).
  2. Boot from Disk: Run the QEMU command again, but REMOVE the -cdrom and -boot d flags. bash qemu-system-x86_64 \ -enable-kvm \ -m 512 \ -drive file=test-disk.qcow2,format=qcow2
  3. Result: If the VM boots and asks for a login, you have successfully initialized a virtual hard drive!

Part D: Managing VMs with libvirt

In Parts A–C, you used raw qemu-img and qemu-system-x86_64 commands to create storage and launch VMs. While this teaches you what happens "under the hood", production environments rarely work this way.

libvirt is an open-source API and management layer that sits on top of hypervisors like KVM/QEMU. It provides a single, consistent interface (virsh CLI, XML configs, and a daemon) that is used by virtually every major virtualisation platform — including Proxmox VE (Lab 2), OpenStack (Week 8+), and oVirt.

Think of it this way:

1. Install libvirt

Install the libvirt daemon, the virsh CLI, and the virt-install provisioning tool:

sudo apt install qemu-kvm libvirt-daemon-system virtinst -y

Verify the service is running:

systemctl status libvirtd

Add your user to the libvirt group so you can manage VMs without sudo:

sudo usermod -aG libvirt $USER

Note: You may need to log out and log back in for the group change to take effect. On the Proxmox shell, you can skip this step as you are already root.

2. Create a Storage Pool and Volume

In Part A, you created a disk with qemu-img create. With libvirt, storage is organised into Pools (directories, LVM groups, NFS mounts, etc.) and Volumes (individual disk images within a pool).

Step 1: Define a Storage Pool

virsh pool-define-as lab-pool dir --target /var/lib/libvirt/images/lab-pool

Step 2: Build, Start, and Auto-start the Pool

virsh pool-build lab-pool
virsh pool-start lab-pool
virsh pool-autostart lab-pool

Step 3: Verify the Pool

virsh pool-list --all

Step 4: Create a Volume (equivalent to qemu-img create -f qcow2)

virsh vol-create-as lab-pool libvirt-test-disk.qcow2 10G --format qcow2

Step 5: Verify the Volume

virsh vol-info libvirt-test-disk.qcow2 --pool lab-pool

3. Deploy a VM with virt-install

In Part B, you used a long qemu-system-x86_64 command to wire up all the virtual hardware. The virt-install tool does the same thing but through libvirt, and it automatically generates the XML domain definition that libvirt uses to manage the VM.

First, copy the Alpine ISO to a location libvirt can access:

sudo cp alpine-virt-3.20.0-x86_64.iso /var/lib/libvirt/images/

Now deploy:

virt-install \
  --name alpine-libvirt \
  --ram 512 \
  --vcpus 1 \
  --disk vol=lab-pool/libvirt-test-disk.qcow2 \
  --cdrom /var/lib/libvirt/images/alpine-virt-3.20.0-x86_64.iso \
  --os-variant alpinelinux3.19 \
  --graphics none \
  --console pty,target_type=serial \
  --boot cdrom

Command Analysis (compare with Part B):

When the VM boots, log in as root (no password) just like in Part B.

Tip: To detach from the console without shutting down the VM, press Ctrl+].

4. Manage the VM with virsh

Now use virsh to manage your running VM — no QEMU commands needed.

List running VMs:

virsh list

Get VM details:

virsh dominfo alpine-libvirt

Reconnect to the console (if you detached earlier):

virsh console alpine-libvirt

Gracefully shut down the VM:

virsh shutdown alpine-libvirt

Start it again:

virsh start alpine-libvirt

Force stop (like pulling the power plug):

virsh destroy alpine-libvirt

Delete the VM definition (clean up when done):

virsh undefine alpine-libvirt

5. Comparison: QEMU CLI vs libvirt

The following table summarises how the raw QEMU commands you used in Parts A–C map to their libvirt equivalents:

Task Raw QEMU Command libvirt / virsh Equivalent
Create a virtual disk qemu-img create -f qcow2 disk.qcow2 10G virsh vol-create-as pool disk.qcow2 10G --format qcow2
Inspect a disk qemu-img info disk.qcow2 virsh vol-info disk.qcow2 --pool pool
Launch a VM qemu-system-x86_64 -enable-kvm -m 512 ... virt-install --name vm --ram 512 ...
List running VMs ps aux | grep qemu virsh list
Shut down a VM poweroff (from inside guest) virsh shutdown vm-name
Force stop a VM Kill the QEMU process virsh destroy vm-name
Start a stopped VM Re-run the full QEMU command virsh start vm-name
Get VM info info in QEMU monitor virsh dominfo vm-name

Critical Thinking:


Lab Checkpoint

Practical Skills Checklist

Theoretical Understanding Checklist

Troubleshooting Scenarios

Scenario 1: qemu-system-x86_64 command errors with "Could not access KVM kernel module"
Solution: [ _________________________________________________________________________ ]

Scenario 2: VM boots but network ping fails
Possible Causes: [ _________________________________________________________________________ ]


Lab Reflection

Take a moment to reflect on what you learned:

  1. Most Valuable Skill: What CLI command or concept will you use most?
    [ _________________________________________________________________________ ]

  2. Biggest Challenge: What was the hardest part of this lab?
    [ _________________________________________________________________________ ]

  3. Real-World Application: When would you use QEMU/KVM directly instead of Proxmox?
    [ _________________________________________________________________________ ]

  4. Next Steps: What virtualization topic do you want to explore further?
    [ _________________________________________________________________________ ]


← Back to Course Index