KVM Virtualization Cookbook

4 (3 reviews total)
By Konstantin Ivanov
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Getting Started with QEMU and KVM

About this book

Virtualization technologies such as KVM allow for better control over the available server resources, by deploying multiple virtual instances on the same physical host, or clusters of compute resources. With KVM it is possible to run various workloads in isolation with the hypervisor layer providing better tenant isolation and higher degree of security.

This book will provide a deep dive into deploying KVM virtual machines using qemu and libvirt and will demonstrate practical examples on how to run, scale, monitor, migrate and backup such instances. You will also discover real production ready recipes on deploying KVM instances with OpenStack and how to programatically manage the life cycle of KVM virtual machines using Python. You will learn numerous tips and techniques which will help you deploy & plan the KVM infrastructure. Next, you will be introduced to the working of libvirt libraries and the iPython development environment.

Finally, you will be able to tune your Linux kernel for high throughput and better performance. By the end of this book, you will gain all the knowledge needed to be an expert in working with the KVM virtualization infrastructure.

Publication date:
June 2017
Publisher
Packt
Pages
340
ISBN
9781788294676

 

Chapter 1. Getting Started with QEMU and KVM

In this chapter, we will cover the following topics:

  • Installing and configuring QEMU
  • Managing disk images with qemu-img
  • Preparing images for OS installation with qemu-nbd
  • Installing a custom OS on the image with debootstrap
  • Resizing an image
  • Using pre-existing images
  • Running virtual machines with qemu-system-*
  • Starting the QEMU VM with KVM support
  • Connecting to a running instance with VNC
 

Introduction


Quick Emulator (QEMU) is the main component of the QEMU/KVM virtualization technology suit. It provides hardware virtualization and processor emulation. QEMU runs in userspace and, without the need for kernel, drivers can still provide fast system emulation. QEMU supports two operating modes:

  • Full system emulation, where QEMU emulates an entire computer system, including the CPU type and peripherals
  • User mode emulation, where QEMU can run a process that has been compiled on a different CPU architecture natively

In this book, we are going to focus on full system emulation with the hardware acceleration support provided by the Kernel-based Virtual Machine (KVM) hypervisor.

In this chapter, we will start by installing QEMU on Linux, then explore various examples of building, managing, and using disk images for the virtual instances. We will then have an in-depth look at running QEMU in full system emulation mode, using the provided binaries. We will see examples of using the KVM kernel module to accelerate the QEMU processes. Finally, we are going to end the chapter with details on how to connect to the virtual machines we started earlier, using VNC clients.

 

Installing and configuring QEMU


In this recipe, we will look at installing QEMU on a single server with the provided distribution packages. For production environments, we recommend using precompiled, packaged versions of QEMU for easier and more consistent deployments. However, we are going to see an example of how to compile QEMU from source, in case you need a certain version that you might want to package later.

Getting ready

Depending on your Linux distribution, the package name and installation commands will differ. You can use your system's package manager, such as apt, dnf, or yum to search for any packages containing the QEMU string and get familiar with what is available for your particular Linux variant. The source code can be downloaded from the official QEMU project website at http://www.qemu-project.org/download/#source.

How to do it...

Perform the following steps to install QEMU from packages on Ubuntu/Debian and RHEL/CentOS distributions:

  1. On Ubuntu/Debian distributions, update your packages index:
[email protected]:~# apt-get update
  1. Install the package:
[email protected]:~# apt-get install -y qemu


  1. On CentOS/RHEL distributions execute:
[email protected]:~# yum install qemu-kvm

To install from source, execute the following:

  1. Download the archive first:
[email protected]:~#cd /usr/src && wget 
http://download.qemu-project.org/qemu-2.8.0.tar.xz
  1. Extract the files from the archive:
[email protected]:/usr/src# tar xvJf qemu-2.8.0.tar.xz && cd qemu-        2.8.0
  1. Configure and compile the source code:
[email protected]:/usr/src/qemu-2.8.0# ./configure  
[email protected]:/usr/src/qemu-2.8.0# make && make install

How it works...

Installing QEMU is quite trivial, as we just saw. Let's have a look at what the QEMU metapackage installed on Ubuntu looks like:

[email protected]:~# dpkg --list | grep qemu
ii ipxe-qemu 1.0.0+git-20150424.a25a16d-1ubuntu1 all PXE boot firmware - ROM images for qemu
ii qemu 1:2.5+dfsg-5ubuntu10.8 amd64 fast processor emulator
ii qemu-block-extra:amd64 1:2.5+dfsg-5ubuntu10.8 amd64 extra block backend modules for qemu-system and qemu-utils
ii qemu-slof 20151103+dfsg-1ubuntu1 all Slimline Open Firmware -- QEMU PowerPC version
ii qemu-system 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries
ii qemu-system-arm 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries (arm)
ii qemu-system-common 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries (common files)
ii qemu-system-mips 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries (mips)
ii qemu-system-misc 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries (miscelaneous)
ii qemu-system-ppc 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries (ppc)
ii qemu-system-sparc 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries (sparc)
ii qemu-system-x86 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU full system emulation binaries (x86)
ii qemu-user 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU user mode emulation binaries
ii qemu-user-binfmt 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU user mode binfmt registration for qemu-user
ii qemu-utils 1:2.5+dfsg-5ubuntu10.8 amd64 QEMU utilities
[email protected]:~#

From the preceding output, we can see that there are few packages involved. If you are interested, you can read the individual description to get more familiar with what each package provides.

It's worth mentioning that all binaries provided from the earlier-mentioned packages start with the prefix QEMU. You can use tab completion to see the list of available executables:

[email protected]:~# qemu-
qemu-aarch64 qemu-io qemu-mips64el qemu-ppc64 qemu-sparc32plus qemu-system-lm32 qemu-system-mipsel qemu-system-sh4 qemu-system-xtensa
qemu-alpha qemu-m68k qemu-mipsel qemu-ppc64abi32 qemu-sparc64 qemu-system-m68k qemu-system-moxie qemu-system-sh4eb qemu-system-xtensaeb
qemu-arm qemu-make-debian-root qemu-mipsn32 qemu-ppc64le qemu-system-aarch64 qemu-system-microblaze qemu-system-or32 qemu-system-sparc qemu-tilegx
qemu-armeb qemu-microblaze qemu-mipsn32el qemu-s390x qemu-system-alpha qemu-system-microblazeel qemu-system-ppc qemu-system-sparc64 qemu-unicore32
qemu-cris qemu-microblazeel qemu-nbd qemu-sh4 qemu-system-arm qemu-system-mips qemu-system-ppc64 qemu-system-tricore qemu-x86_64
qemu-i386 qemu-mips qemu-or32 qemu-sh4eb qemu-system-cris qemu-system-mips64 qemu-system-ppc64le qemu-system-unicore32
qemu-img qemu-mips64 qemu-ppc qemu-sparc qemu-system-i386 qemu-system-mips64el qemu-system-ppcemb qemu-system-x86_64
[email protected]:~#

We can see that there's a single executable for each CPU architecture type that can be emulated.

 

Managing disk images with qemu-img


To run virtual machines, QEMU needs images to store the filesystem of the guest OS. The image itself is a type of file, and it represents the guest filesystem residing on a virtual disk. QEMU supports various images and provides tools to create and manage them. In this recipe, we are going to build a blank disk image with the qemu-img utility.

Getting ready

To use this recipe, we need to have the qemu-img utility installed. If you followed the steps in the first recipe, you should have that covered. To check what image types are supported on your Linux distribution, run the following command:

[email protected]:~# qemu-img -h | grep Supported
Supported formats: bochs vvfat rbd vpc parallels tftp ftp ftps raw https qcow dmg http qcow2 quorum null-aio cloop vdi iscsi null-co vhdx blkverify file vmdk host_cdrom blkdebug host_device sheepdog qed nbd
[email protected]:~#

From the preceding output, we can see that there are many supported images on the test system that we are using. Make sure that your QEMU version supports the raw image type, as it's the default and that is what we are going to use in this recipe. One of the most commonly used image type is qcow2, which supports copy on write, compression, encryption, and snapshotting. We are going to leverage that in later recipes.

Note

Please note that even though QEMU supports multiple formats, that does not necessarily mean that you can run virtual machines on them. However, qemu-img can be used to convert different images to raw and qcow2 formats. For best performance, use raw or qcow2 image formats.

How to do it...

Perform the following steps to create a blank raw image of a specified size and to verify that the file was created on the host:

  1. Create a raw image named debian.img with size of 10 GB:
[email protected]:~# qemu-img create -f raw debian.img 10G    
Formatting 'debian.img', fmt=raw size=10737418240    
[email protected]:~#
  1. Check that the file was created:
[email protected]:~# ls -lah debian.img    
-rw-r--r-- 1 root root 10G Feb 10 16:58 debian.img    
 [email protected]:~#


  1. Examine the file type:
[email protected]:~# file -s debian.img    
debian.img: data    
[email protected]:~#
  1. Obtain more information about the image:
[email protected]:~# qemu-img info debian.img
image: debian.img
file format: raw
virtual size: 10G (10737418240 bytes)
disk size: 0
[email protected]:~#

How it works...

The qemu-img utility allows us to create, convert, and modify guest images.

In step 1, we used the -f flag specifying the image format; in this case, raw, the name of the image to be created and the size in gigabytes.

In step 4, we used the info subcommand to gather additional information about the existing image. Note how the disk size is showing as currently being zero. This is due to the fact that this is a blank image, not containing a filesystem. We are going to create one in the next recipe.

There's more...

In this recipe, we listed the supported disk image formats by QEMU. The following is a brief description of the most common types that you might encounter:

  • raw: Raw disk image format. This is the default format and can be one of the fastest file-based formats. If you format this image with a filesystem that supports holes, for example, EXT3, then only sectors that have data will use space. The main drawback of the raw images is the lack of features, making them ideal for testing and quick prototyping.
  • qcow2: As we mentioned in the previous section, this is one of the most feature-rich formats. It supports VM snapshots, compression, and encryption for the price of slightly reduced performance.
  • qcow: This is an older QEMU image format that supports backing files, compact image files, encryption, and compression.
  • dmg: This is the Mac disk image format. The Mac disk image provides secure password protection and compression, and it is most commonly used to distribute software, rather than running virtual machines.
  • nbd: The network block device, typically used for accessing remote storage devices.
  • vdi: This disk format is used by the Oracle VirtualBox software and can be used to run virtual machines on various CPU platforms.
  • vmdk: This is the VMware disk image type, where a single virtual hard disk can span multiple files.
  • vhdx: Microsoft Hyper-V uses this image format. It provides large storage capacity, data corruption protection during power failures and read/write optimization for larger disk images.

In this book, we are going to use the raw and qcow2 disk formats, as they provide the best performance and toolset for running and manipulating them.

 

Preparing images for OS installation with qemu-nbd


In the previous recipe, we created a blank raw image. In this recipe, we are going to make a partition and a filesystem on it, getting the image ready for full guest OS installation. When creating the partition and file system, you should consider the type of load that the virtual instance will create. If your applications running inside VM are IO bound, you might consider XFS for the image filesystem. For this recipe, we are going to use EXT4, as most Linux distributions support it out of the box.

Getting ready

For this recipe, we are going to use the following tools:

  • qemu-nbd
  • sfdisk
  • The nbd kernel module
  • mkfs

Most Linux distributions should already have the tools installed. If that's not the case, consult your distribution's documentation on how to install them.

How to do it...

Perform the following steps outlined to partition and create a filesystem on the blank image:

  1. Load the nbd kernel module:
    [email protected]:~# modprobe nbd
    [email protected]:~#
  1. Using the qemu-nbd tool, associate the blank image file to the /dev/nbd0 block device:
[email protected]:~# qemu-nbd --format=raw --connect=/dev/nbd0          debian.img  
[email protected]:~#
  1. Create two partitions on the block device. One will be used for swap, and the other as the root partition for the guest OS:
[email protected]:~# sfdisk /dev/nbd0 << EOF    
>,1024,82    
>;    
>EOF    
Checking that no-one is using this disk right now ...
OK
Disk /dev/nbd0: cannot get geometry

Disk /dev/nbd0: 1305 cylinders, 255 heads, 63 sectors/track

sfdisk: ERROR: sector 0 does not have an msdos signature
 /dev/nbd0: unrecognized partition table type
Old situation:
No partitions found
New situation:
Units = cylinders of 8225280 bytes, blocks of 1024 bytes, counting from 0

 Device Boot Start End #cyls #blocks Id System
/dev/nbd0p1 0+ 1023 1024- 8225279+ 82 Linux swap / Solaris
/dev/nbd0p2 1024 1304 281 2257132+ 83 Linux
/dev/nbd0p3 0 - 0 0 0 Empty
/dev/nbd0p4 0 - 0 0 0 Empty
Warning: no primary partition is marked bootable (active)
This does not matter for LILO, but the DOS MBR will not boot this disk.
Successfully wrote the new partition table

Re-reading the partition table ...

If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)
to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1
(See fdisk(8).)
[email protected]:~#
  1. List the available block devices after the partitioning:
[email protected]:~# ls -la /dev/nbd0*    
brw-rw---- 1 root disk 43, 0 Feb 10 18:24 /dev/nbd0    
brw-rw---- 1 root disk 43, 1 Feb 10 18:24 /dev/nbd0p1    
brw-rw---- 1 root disk 43, 2 Feb 10 18:24 /dev/nbd0p2    
[email protected]:~#
  1. Create the swap partition:
[email protected]:~# mkswap /dev/nbd0p1    
Setting up swapspace version 1, size = 508 KiB (520192 bytes)    
no label, UUID=c246fe39-1bc5-4978-967c-806264771d69    
[email protected]:~#
  1. Make the EXT4 filesystem on the root partition:
[email protected]:~# mkfs.ext4 /dev/nbd0p2    
mke2fs 1.42.13 (17-May-2015)    
Discarding device blocks: failed - Input/output error    
Creating filesystem with 2620928 4k blocks and 655360 inodes    
Filesystem UUID: 2ffa23de-579a-45ad-abbc-2a179de67f11    
Superblock backups stored on blocks:    
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632    
Allocating group tables: done    
Writing inode tables: done    
Creating journal (32768 blocks): done    
Writing superblocks and filesystem accounting information: done    
[email protected]:~#

How it works...

We take advantage of the functionality that the nbd kernel module provides by allowing us to associate a raw image file to a block device using the qemu-nbd utility. To get more information about the kernel module run the following code:

[email protected]:~# modinfo nbd
filename: /lib/modules/4.4.0-62-generic/kernel/drivers/block/nbd.ko
license: GPL
description: Network Block Device
srcversion: C67096AF2AE3C738DBE0B7E
depends:
intree: Y
vermagic: 4.4.0-62-generic SMP mod_unload modversions
parm: nbds_max:number of network block devices to initialize (default: 16) (int)
parm: max_part:number of partitions per device (default: 0) (int)
[email protected]:~#

We can examine the block device metadata created in step 2 by running the following command:

[email protected]:~# file -s /dev/nbd0
/dev/nbd0: x86 boot sector
[email protected]:~#

After creating the two new partitions in step 3, the type of the image file has changed. Let's examine it again:

[email protected]:~# file -s debian.img
debian.img: x86 boot sector
[email protected]:~#

Note

We chose to use the sfdisk utility to create the partitions, but you can use the fdisk utility interactively instead if you prefer. The end result will be the same.

Now that we have an image file that contains two partitions and a filesystem, we can proceed with installing the guest OS in the next recipe.

 

Installing a custom OS on the image with debootstrap


In this recipe, we are going to use the debootstrap utility to install a Debian distribution on the raw image we prepared in the previous two recipes. The debootstrap command is used to bootstrap a basic Debian system using a specific public mirror. By the end of this recipe, we should have an image containing an entire Linux distribution, ready for QEMU execution.

Getting ready

We are going to need the following in order to complete this recipe:

  • The block devices created in the previous recipe
  • The debootstrap utility
  • The chroot utility

To ensure that the swap and root block devices are still present on the system, run the following:

[email protected]:~# ls -la /dev/nbd0*
brw-rw---- 1 root disk 43, 0 Feb 10 18:24 /dev/nbd0
brw-rw---- 1 root disk 43, 1 Feb 10 18:24 /dev/nbd0p1
brw-rw---- 1 root disk 43, 2 Feb 10 18:24 /dev/nbd0p2
[email protected]:~#

If that's not the case, please refer to the Preparing images for OS installation with qemu-nbd recipe on how to associate the raw image with the /deb/nbd0 block device.

To install the debootstrap utility, if not already present on your system, execute the following code:

[email protected]:~# apt install -y debootstrap
...
Setting up debootstrap (1.0.78+nmu1ubuntu1.2) ...
[email protected]:~#

How to do it...

Follow these steps outlined to install a new Debian Linux distribution on the raw image:

  1. Mount the root partition from the Network Block Device (NBD) device and ensure that it was mounted successfully:
[email protected]:~# mount /dev/nbd0p2 /mnt/    
[email protected]:~# mount | grep mnt    
/dev/nbd0p2 on /mnt type ext4 (rw) 
[email protected]:~#
  1. Install the latest stable Debian distribution on the root partition mounted on /mnt from the specified public repository:
[email protected]:~# debootstrap --arch=amd64 --include="openssh-server vim" stable /mnt/ http://httpredir.debian.org/debian/    
...    
I: Base system installed successfully.    
[email protected]:~#
  1. Ensure the root filesystem was created, by listing all the files at the mounted location:
[email protected]:~# ls -lah /mnt/    
total 100K    drwxr-xr-x 22 root root 4.0K Feb 10 17:19 .    
drwxr-xr-x 23 root root 4.0K Feb 10 15:29 ..    
drwxr-xr-x 2 root root 4.0K Feb 10 17:19 bin    
drwxr-xr-x 2 root root 4.0K Dec 28 17:42 boot    
drwxr-xr-x 4 root root 4.0K Feb 10 17:18 dev    
drwxr-xr-x 55 root root 4.0K Feb 10 17:19 etc    
drwxr-xr-x 2 root root 4.0K Dec 28 17:42 home    
drwxr-xr-x 12 root root 4.0K Feb 10 17:19 lib    
drwxr-xr-x 2 root root 4.0K Feb 10 17:18 lib64    
drwx------ 2 root root 16K Feb 10 17:06 lost+found    
drwxr-xr-x 2 root root 4.0K Feb 10 17:18 media    
drwxr-xr-x 2 root root 4.0K Feb 10 17:18 mnt    
drwxr-xr-x 2 root root 4.0K Feb 10 17:18 opt    
drwxr-xr-x 2 root root 4.0K Dec 28 17:42 proc    
drwx------ 2 root root 4.0K Feb 10 17:18 root    
drwxr-xr-x 4 root root 4.0K Feb 10 17:19 run    
drwxr-xr-x 2 root root 4.0K Feb 10 17:19 sbin    
drwxr-xr-x 2 root root 4.0K Feb 10 17:18 srv    
drwxr-xr-x 2 root root 4.0K Apr 6 2015 sys    
drwxrwxrwt 2 root root 4.0K Feb 10 17:18 tmp    
drwxr-xr-x 10 root root 4.0K Feb 10 17:18 usr    
drwxr-xr-x 11 root root 4.0K Feb 10 17:18 var    
[email protected]:~#
  1. Bind and mount the devices directory from the host to the image filesystem:
[email protected]:~# mount --bind /dev/ /mnt/dev    
[email protected]:~#
  1. Ensure that the nbd devices are now present inside the mount location:
[email protected]:~# ls -la /mnt/dev/ | grep nbd0    
brw-rw---- 1 root disk 43, 0 Feb 10 18:24 nbd0    
brw-rw---- 1 root disk 43, 1 Feb 10 18:26 nbd0p1    
brw-rw---- 1 root disk 43, 2 Feb 10 18:26 nbd0p2    
[email protected]:~#
  1. Change the directory namespace to be the root filesystem of the image and ensure the operation succeeded:
[email protected]:~# chroot /mnt/    
[email protected]:/# pwd
/    
[email protected]:/#
  1. Check the distribution version inside the chroot environment:
[email protected]:/# cat /etc/debian_version
8.7    
[email protected]:/#
  1. Mount the proc and sysfs virtual filesystems inside the chrooted environment:
[email protected]:/# mount -t proc none /proc    
[email protected]:/# mount -t sysfs none /sys    
[email protected]:/#
  1. While still inside the chrooted location, install the Debian kernel metapackage and the grub2 utilities:
[email protected]:/# apt-get install -y --force-yes linux-image-amd64 grub2

Note

If asked to select target device for GRUB to install on, do not select any and just continue.

  1. Install GRUB on the root device:
[email protected]:/# grub-install /dev/nbd0 --force   
Installing for i386-pc platform.
grub-install: warning: this msdos-style partition label has no post-MBR gap; embedding won't be possible.
grub-install: warning: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and their use is discouraged..
Installation finished. No error reported.    
[email protected]:/#
  1. Update the GRUB configs and the initrd image:
[email protected]:/# update-grub2    
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.16.0-4-amd64
Found initrd image: /boot/initrd.img-3.16.0-4-amd64
done   
[email protected]:/#
  1. Change the root password of the guest:
[email protected]:/# passwd    
Enter new UNIX password:    
Retype new UNIX password:    
passwd: password updated successfully    
[email protected]:/#
  1. Allow access to the pseudo Terminal inside the new guest OS:
[email protected]:/# echo "pts/0" >> /etc/securetty    
[email protected]:/#
  1. Change the systemd run level to the multi-user level:
[email protected]:/# systemctl set-default multi-user.target    
Created symlink from /etc/systemd/system/default.target to /lib/systemd/system/multi-user.target.    
[email protected]:/#


  1. Add the root mountpoint to the fstab file, so it can persist reboots:
[email protected]:/# echo "/dev/sda2 / ext4 defaults,discard 0 0" > /etc/fstab
  1. Unmount the following filesystems as we are done using them for now:
[email protected]:/# umount /proc/ /sys/ /dev/
  1. Exit the chrooted environment:
[email protected]:/# exit    
exit    
[email protected]:~#
  1. Install GRUB on the root partition of the block device associated with the raw image:
[email protected]:~# grub-install /dev/nbd0 --root-directory=/mnt --modules="biosdisk part_msdos" --force 
Installing for i386-pc platform.
grub-install: warning: this msdos-style partition label has no post-MBR gap; embedding won't be possible.
grub-install: warning: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and their use is discouraged..
Installation finished. No error reported.    
[email protected]:~#
  1. Update the GRUB configuration file to reflect the correct block device for the guest image:
[email protected]:~# sed -i 's/nbd0p2/sda2/g' /mnt/boot/grub/grub.cfg    
[email protected]:~#
  1. Unmount the nbd0 device:
[email protected]:~# umount /mnt    
[email protected]:~#
  1. Disassociate the nbd0 device from the raw image:
[email protected]:~# qemu-nbd --disconnect /dev/nbd0    
/dev/nbd0 disconnected    
[email protected]:~#

How it works...

A lot has happened in the previous section, so let's step through the commands and talk a little bit more about what exactly was performed and why.

In step 1, we mounted the root partition we created earlier on the /dev/nbd0p2 device to /mnt, so we can use it. Once mounted, in step 2, we installed an entire Debian distribution on that device using the mount-point as the target.

In order to install the GRUB boot loader on the root partition of the image, we bind and mounted the /dev directory from the host filesystem to the image filesystem in /mnt in step 4.

Then in step 6, we used the chroot tool to change our directory namespace to be /mnt, so we can perform operations, as we are directly on the new OS.

In step 8, we mounted the proc and sysfs virtual filesystems inside the image because the GRUB bootloader tool expect them.

In step 9, we proceeded to install the kernel source and GRUB tools in preparation of installing the bootloader on the boot partition and in step 10 we installed the bootloader.

In step 11, the GRUB configuration files were generated and the boot ramdisk image was updated.

In steps 12, 13, and 14, we changed the root password and ensured we get access to the pseudo Terminal, so we can log into the VM later and change the run-level from the default graphical interface to the multiuser.

Since the fstab file is empty right after installing the Debian OS on the image, we have to add the root mount point, or the VM will not be able to start. This was accomplished in step 15.

In steps 16 and 17, we performed some cleaning up by unmounting the filesystems we mounted earlier and exited the chroot environment.

Back on the host filesystem in step 18, we installed GRUB on the nbd0 device by specifying the mounted location of the image.

In step 19, we updated the GRUB config device name to be sda2 because this is the name that will appear inside the virtual machine once we start it. The nbd0p2 name is only present while we have the association between the raw image and the network block device on the host OS. From the VM perspective, the second partition inside the image we created by is named sda2 by default.

And finally, in steps 20 and 21, we performed some cleaning by removing the mount point and disassociating the raw image from the network block device nbd0.

 

Resizing an image


In this recipe, we are going to examine how to resize an existing raw image, the partitions hosted on it and the filesystem on top of the partitions. We are going to be using the raw image that we build in the previous recipes, which contains a swap and a root partition with an EXT4 filesystem formatted on it.

Getting ready

For this recipe, we are going to use the following tools:

  • qemu-img
  • losetup
  • tune2fs
  • e2fsck
  • kpartx
  • fdisk
  • resize2fs

Most of the utilities should already be installed on Ubuntu with the exception of kpartx. To install it, run the following:

[email protected]:~# apt install kpartx

How to do it...

The next steps demonstrate how to add additional space to the raw image we created earlier, extend the root partition, and resize the filesystem. By the end of this recipe, the original raw image filesystem size should have changed from 10G to 20G.

  1. Obtain the current size of the image:
[email protected]:~# qemu-img info debian.img    
image: debian.img
file format: raw
virtual size: 10G (10737418240 bytes)
disk size: 848M    
[email protected]:~#
  1. Add additional 10 GB to the image:
[email protected]:~# qemu-img resize -f raw debian.img +10GB    
Image resized.    
[email protected]:~#

Note

Please note that not all image types support resizing. In order to resize such an image, you will need to convert it to raw image first using the qemu-img convert command.

  1. Check the new size of the image:
[email protected]:~# qemu-img info debian.img    
image: debian.img
file format: raw
virtual size: 20G (21474836480 bytes)
disk size: 848M   
[email protected]:~#
  1. Print the name of the first unused loop device:
[email protected]:~# losetup -f 
/dev/loop0    
[email protected]:~#
  1. Associate the first unused loop device with the raw image file:
[email protected]:~# losetup /dev/loop1 debian.img    
[email protected]:~#
  1. Read the partition information from the associated loop device and create the device mappings:
[email protected]:~# kpartx -av /dev/loop1    
add map loop1p1 (252:0): 0 1024 linear 7:1 2048    
add map loop1p2 (252:1): 0 20967424 linear 7:1 4096
[email protected]:~#


  1. Examine the new device maps, representing the partitions on the raw image:
[email protected]:~# ls -la /dev/mapper    
total 0    
drwxr-xr-x 2 root root 100 Mar 9 19:10 .    
drwxr-xr-x 20 root root 4760 Mar 9 19:10 ..    
crw------- 1 root root 10, 236 Feb 10 23:25 control    
lrwxrwxrwx 1 root root 7 Mar 9 19:10 loop1p1    
lrwxrwxrwx 1 root root 7 Mar 9 19:10 loop1p2    
[email protected]:~#
  1. Obtain some information from the root partition mapping:
[email protected]:~# tune2fs -l /dev/mapper/loop1p2    
tune2fs 1.42.13 (17-May-2015)    
Filesystem volume name: <none>    
Last mounted on: /    
Filesystem UUID: 96a73752-489a-435c-8aa0-8c5d1aba3e5f    
Filesystem magic number: 0xEF53    
Filesystem revision #: 1 (dynamic)    
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super            large_file huge_file uninit_bg dir_nlink extra_isize    Filesystem flags: signed_directory_hash    
Default mount options: user_xattr acl    
Filesystem state: clean    
Errors behavior: Continue    
Filesystem OS type: Linux    
Inode count: 655360    
Block count: 2620928    
Reserved block count: 131046    
Free blocks: 2362078    
Free inodes: 634148    
First block: 0    
Block size: 4096    
Fragment size: 4096    
Reserved GDT blocks: 639    
Blocks per group: 32768    
Fragments per group: 32768    
Inodes per group: 8192    
Inode blocks per group: 512    
Flex block group size: 16    
Filesystem created: Fri Feb 10 23:29:01 2017    
Last mount time: Thu Mar 9 19:09:25 2017    
Last write time: Thu Mar 9 19:08:23 2017    
Mount count: 12    
Maximum mount count: -1    
Last checked: Fri Feb 10 23:29:01 2017    
Check interval: 0 (<none>)    
Lifetime writes: 1621 MB    
Reserved blocks uid: 0 (user root)    
Reserved blocks gid: 0 (group root)    
First inode: 11    
Inode size: 256    
Required extra isize: 28    
Desired extra isize: 28    
Journal inode: 8    
Default directory hash: half_md4    
Directory Hash Seed: f101cccc-944e-4773-8644-91ebf4bd4f2d    
Journal backup: inode blocks    
[email protected]:~#
  1. Check the filesystem on the root partition of the mapped device:
[email protected]:~# e2fsck /dev/mapper/loop1p2    
e2fsck 1.42.13 (17-May-2015)    
/dev/mapper/loop1p2: recovering journal    Setting free blocks count to 2362045 (was 2362078)    /dev/mapper/loop1p2: clean, 21212/655360 files, 258883/2620928 blocks    
[email protected]:~#
  1. Remove the journal from the root partition device:
[email protected]:~# tune2fs -O ^has_journal /dev/mapper/loop1p2    
tune2fs 1.42.13 (17-May-2015)    
[email protected]:~#
  1. Ensure that the journaling has been removed:
[email protected]:~# tune2fs -l /dev/mapper/loop1p2 | grep "features"    
Filesystem features: ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg     dir_nlink extra_isize    
[email protected]:~#
  1. Remove the partition mappings:
[email protected]:~# kpartx -dv /dev/loop1    
del devmap : loop1p2    
del devmap : loop1p1    
[email protected]:~#


  1. Detach the loop device from the image:
[email protected]:~# losetup -d /dev/loop1    
[email protected]:~#
  1. Associate the raw image with the network block device:
[email protected]:~# qemu-nbd --format=raw --connect=/dev/nbd0 debian.img  [email protected]:~#
  1. Using fdisk, list the available partitions, then delete the root partition, recreate it, and write the changes:
[email protected]:~# fdisk /dev/nbd0    

Command (m for help): p

Disk /dev/nbd0: 21.5 GB, 21474836480 bytes
255 heads, 63 sectors/track, 2610 cylinders, total 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

 Device Boot Start End Blocks Id System
/dev/nbd0p1 1 16450559 8225279+ 82 Linux swap / Solaris
/dev/nbd0p2 16450560 20964824 2257132+ 83 Linux

Command (m for help): d
Partition number (1-4): 2

Command (m for help): n
Partition type:
 p primary (1 primary, 0 extended, 3 free)
 e extended
Select (default p): p
Partition number (1-4, default 2): 2
First sector (16450560-41943039, default 16450560):
Using default value 16450560
Last sector, +sectors or +size{K,M,G} (16450560-41943039, default 41943039):
Using default value 41943039

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
[email protected]:~#
  1. Associate the first unused loop device with the raw image file, like we did in step 5:
[email protected]:~# losetup /dev/loop1 debian.img
  1. Read the partition information from the associated loop device and create the device mappings:
[email protected]:~# kpartx -av /dev/loop1    
add map loop1p1 (252:2): 0 1024 linear 7:1 2048    
add map loop1p2 (252:3): 0 41938944 linear 7:1 4096    
[email protected]:~#
  1. After the partitioning is complete, perform a filesystem check:
[email protected]:~# e2fsck -f /dev/mapper/loop1p2    
e2fsck 1.42.13 (17-May-2015)    
Pass 1: Checking inodes, blocks, and sizes    
Pass 2: Checking directory structure    
Pass 3: Checking directory connectivity    
Pass 4: Checking reference counts    
Pass 5: Checking group summary information    
/dev/mapper/loop1p2: 21212/655360 files (0.2% non-contiguous), 226115/2620928 blocks    
[email protected]:~#
  1. Resize the filesystem on the root partition of the mapped device:
[email protected]:~# resize2fs /dev/nbd0p2 
resize2fs 1.42.13 (17-May-2015) 
Resizing the filesystem on /dev/mapper/loop1p2 to 5242368 (4k) blocks. 
The filesystem on /dev/mapper/loop1p2 is now 5242368 (4k) blocks long. 
[email protected]:~#
  1. Create the filesystem journal because we removed it earlier:
[email protected]:~# tune2fs -j /dev/mapper/loop1p2    
tune2fs 1.42.13 (17-May-2015)    
Creating journal inode: done    
[email protected]:~#


  1. Remove the device mappings:
[email protected]:~# kpartx -dv /dev/loop1    
del devmap : loop1p2    
del devmap : loop1p1    
[email protected]:~# losetup -d /dev/loop1    
[email protected]:~#

How it works...

Resizing an image for VM can be somewhat involving, as we saw from all the steps in the previous section. Things can get complicated when there are multiple Linux partitions inside the same image, even more so if we are not using Logical Volume Management (LVM). Let's step through all the commands we ran earlier and explain in more details why we ran them and what they do.

In step 1, we confirmed the current size of the image being 10 GB.

In step 2, we added 10 GB at the end of the image and confirm the new image size in step 3.

Recall that the image we built from earlier recipes contains two partitions, swap and root. We need a way to manipulate them individually. Particularly, we would like to allocate the extra space we added in step 2 to the root partition. To do that we need to expose it as a block device that we can easily manipulate with standard disk and filesystem utilities. We accomplished that using the losetup command in step 5, resulting in a mapping between the image and a new block device named /dev/loop1. In step 6, we exposed the individual partitions as two new device mappings. The /dev/mapper/loop1p2 is the root partition that we would like to append the unused disk space to.

Before we can resize the partitioned on the loop device, we need to check the integrity of the filesystem on it, and this is what we did in step 9. Because we are using a journaling filesystem, we need to remove the journal prior to resizing. We do that in step 10 and made sure that the has_journal attribute is not showing after running the tune2fs command in step 11.

Now, we need to work directly on the main block device and not the individual partitions. We remove the mappings in steps 12 and 13 and associated a new block device with the image file using the qemu-nbd command in step 14. The new /dev/nbd0 block device now represents the entire disk of the guest VM and it's a direct mapping to what's inside the raw image. We can use this block device just like any other regular disk, most importantly we can use tools such as fdisk to examine and manipulate the partitions residing on it.

In step 15, we use the fdisk utility to delete the root partition and recreate it. This does not destroy any filesystem data, but changes the metadata, allocating the extra space we added earlier as part of the root partition.

Now that the block device has all the disk space allocated to the root partition, we need to extend the filesystem that is on top of it. We do that by first recreating the individual partition mappings like we did earlier, to expose the root partition directly so that we can yet again manipulate it. We do that in steps 16 and 17.

In steps 18 and 19, we check the integrity of the root file system, then we resize it to the maximum available disk space on the root partition that it resides.

Finally, in step 20, we remove the mappings again. Now the image, the root partition inside the image, and the EXT4 filesystem on top of the Linux partition have been resized to 20 GB.

You can check the new root partition size by starting a new QEMU instance using the image. We are going to do just that in a separate recipe in this chapter.

 

Using pre-existing images


In the Installing a custom OS on the image with debootstrap recipe, we saw how to use the debootstrap command to install Debian on an image we built. Most Linux vendors provide already built images of their distributions for various architectures. Installable images are also available for manually installing the guest OS. In this recipe, we are going to demonstrate how to obtain and examine CentOS and Debian images that have already been built. In a later recipe, we are going to show how to start QEMU/KVM instances using those same images.

Getting ready

For this recipe, we are going to need QEMU installed on the host OS. For instructions on how to install QEMU, please refer to the Installing and configuring QEMU recipe from this chapter. We are also going to need the wget utility to download the images from the upstream public repositories.

How to do it...

To obtain Debian Wheezy images for use with QEMU and KVM, perform the following:

  1. Download the image using wget:
[email protected]:~tmp# wget https://people.debian.org/~aurel32/qemu/amd64/debian_wheezy_amd64_standard.qcow2    
--2017-03-09 22:07:20-- 2    Resolving people.debian.org (people.debian.org)... 2001:41c8:1000:21::21:30, 5.153.231.30    Connecting to people.debian.org (people.debian.org)|2001:41c8:1000:21::21:30|:443... connected.    HTTP request sent, awaiting response... 200 OK    Length: 267064832 (255M)    Saving to: ‘debian_wheezy_amd64_standard.qcow2’    debian_wheezy_amd64_standard.qcow2 100% .  [===================================>] 254.69M 35.8MB/s in 8.3s    2017-03-09 22:07:29 (30.9 MB/s) - ‘debian_wheezy_amd64_standard.qcow2’ saved [267064832/267064832]    
[email protected]:~#
  1. Inspect the type of the image:
[email protected]:~# qemu-img info debian_wheezy_amd64_standard.qcow2    
image: debian_wheezy_amd64_standard.qcow2    
file format: qcow2    
virtual size: 25G (26843545600 bytes)    
disk size: 261M    
cluster_size: 65536    
Format specific information:    
compat: 1.1    
lazy refcounts: false    
refcount bits: 16    
corrupt: false    
[email protected]:~#

To download CentOS images run the following commands:

  1. Download the image using wget:
[email protected]:/tmp# wget         https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2    --2017-03-09 22:11:34-- https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2    Resolving cloud.centos.org (cloud.centos.org)... 2604:4500::2a8a, 136.243.75.209    Connecting to cloud.centos.org (cloud.centos.org)|2604:4500::2a8a|:443... connected.    HTTP request sent, awaiting response... 200 OK    Length: 1361182720 (1.3G)    Saving to: ‘CentOS-7-x86_64-GenericCloud.qcow2’
CentOS-7-x86_64-GenericCloud.qcow2 100%[=========================================>] 1.27G 22.3MB/s in 54s
2017-03-09 22:12:29 (24.0 MB/s) - ‘CentOS-7-x86_64-GenericCloud.qcow2’ saved [1361182720/1361182720]
FINISHED --2017-03-09 22:12:29--    Total wall clock time: 54s    Downloaded: 1 files, 1.3G in 54s (24.0 MB/s)    
[email protected]:/tmp#
  1. Inspect the type of the image:
[email protected]:~# qemu-img info CentOS-7-x86_64-GenericCloud.qcow2    
image: CentOS-7-x86_64-GenericCloud.qcow2    
file format: qcow2    
virtual size: 8.0G (8589934592 bytes)    
disk size: 1.3G    
cluster_size: 65536    
Format specific information:    
compat: 0.10    
refcount bits: 16    
[email protected]:~#

How it works...

There are many public repositories on the Internet that provide images of various types, most commonly qcow2 for use with QEMU/KVM. In the previous section, we used the official CentOS repository to obtain the image and an another one containing prebuilt images for Debian.

Both images are in the qcow2 format, as we confirmed in step 2.

There's more...

So far, we've only seen how to build, examine, manipulate, and download images. In the next recipe, we are going to focus on how to actually use the images to start QEMU/KVM instances.

See also

Examine the following links to get more information about what prebuilt images are available for the listed distributions:

 

Running virtual machines with qemu-system-*


In this recipe, we are going to demonstrate how to start virtual machines with QEMU. QEMU provides binaries that can emulate different CPU architectures using either custom or prebuilt images for the guest OS.

If you completed the Installing and configuring QEMU recipe, you should have a host that contains the following binaries:

[email protected]:~# ls -la /usr/bin/qemu-system-*
-rwxr-xr-x 1 root root 8868848 Jan 25 12:49 /usr/bin/qemu-system-aarch64
-rwxr-xr-x 1 root root 7020544 Jan 25 12:49 /usr/bin/qemu-system-alpha
-rwxr-xr-x 1 root root 8700784 Jan 25 12:49 /usr/bin/qemu-system-arm
-rwxr-xr-x 1 root root 3671488 Jan 25 12:49 /usr/bin/qemu-system-cris
-rwxr-xr-x 1 root root 8363680 Jan 25 12:49 /usr/bin/qemu-system-i386
-rwxr-xr-x 1 root root 3636640 Jan 25 12:49 /usr/bin/qemu-system-lm32
-rwxr-xr-x 1 root root 6982528 Jan 25 12:49 /usr/bin/qemu-system-m68k
-rwxr-xr-x 1 root root 3652224 Jan 25 12:49 /usr/bin/qemu-system-microblaze
-rwxr-xr-x 1 root root 3652224 Jan 25 12:49 /usr/bin/qemu-system-microblazeel
-rwxr-xr-x 1 root root 8132992 Jan 25 12:49 /usr/bin/qemu-system-mips
-rwxr-xr-x 1 root root 8356672 Jan 25 12:49 /usr/bin/qemu-system-mips64
-rwxr-xr-x 1 root root 8374336 Jan 25 12:49 /usr/bin/qemu-system-mips64el
-rwxr-xr-x 1 root root 8128896 Jan 25 12:49 /usr/bin/qemu-system-mipsel
-rwxr-xr-x 1 root root 3578592 Jan 25 12:49 /usr/bin/qemu-system-moxie
-rwxr-xr-x 1 root root 3570848 Jan 25 12:49 /usr/bin/qemu-system-or32
-rwxr-xr-x 1 root root 8701760 Jan 25 12:49 /usr/bin/qemu-system-ppc
-rwxr-xr-x 1 root root 9048000 Jan 25 12:49 /usr/bin/qemu-system-ppc64
lrwxrwxrwx 1 root root 17 Jan 25 12:49 /usr/bin/qemu-system-ppc64le -> qemu-system-ppc64
-rwxr-xr-x 1 root root 8463680 Jan 25 12:49 /usr/bin/qemu-system-ppcemb
-rwxr-xr-x 1 root root 6894528 Jan 25 12:49 /usr/bin/qemu-system-sh4
-rwxr-xr-x 1 root root 6898624 Jan 25 12:49 /usr/bin/qemu-system-sh4eb
-rwxr-xr-x 1 root root 4032000 Jan 25 12:49 /usr/bin/qemu-system-sparc
-rwxr-xr-x 1 root root 7201696 Jan 25 12:49 /usr/bin/qemu-system-sparc64
-rwxr-xr-x 1 root root 3704704 Jan 25 12:49 /usr/bin/qemu-system-tricore
-rwxr-xr-x 1 root root 3554912 Jan 25 12:49 /usr/bin/qemu-system-unicore32
-rwxr-xr-x 1 root root 8418656 Jan 25 12:49 /usr/bin/qemu-system-x86_64
-rwxr-xr-x 1 root root 3653024 Jan 25 12:49 /usr/bin/qemu-system-xtensa
-rwxr-xr-x 1 root root 3642752 Jan 25 12:49 /usr/bin/qemu-system-xtensaeb
[email protected]:~#

Each command can start a QEMU-emulated instance for the specific CPU architecture. For this recipe, we are going to be using the qemu-system-x86_64 utility.

Getting ready

To complete this recipe, you will need the following:

  • The QEMU binaries, provided after following the Installing and configuring QEMU recipe
  • The custom raw Debian image we built in the Installing a custom OS on the image with debootstrap recipe
  • The CentOS qcow2 image we downloaded in the Using pre-existing images recipe

Let's have a look at what CPU architectures QEMU supports on the host system:

[email protected]:~# qemu-system-x86_64 --cpu help
x86 qemu64 QEMU Virtual CPU version 2.5+
x86 phenom AMD Phenom(tm) 9550 Quad-Core Processor
x86 core2duo Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz
x86 kvm64 Common KVM processor
x86 qemu32 QEMU Virtual CPU version 2.5+
x86 kvm32 Common 32-bit KVM processor
x86 coreduo Genuine Intel(R) CPU T2600 @ 2.16GHz
x86 486
x86 pentium
x86 pentium2
x86 pentium3
x86 athlon QEMU Virtual CPU version 2.5+
x86 n270 Intel(R) Atom(TM) CPU N270 @ 1.60GHz
x86 Conroe Intel Celeron_4x0 (Conroe/Merom Class Core 2)
x86 Penryn Intel Core 2 Duo P9xxx (Penryn Class Core 2)
x86 Nehalem Intel Core i7 9xx (Nehalem Class Core i7)
x86 Westmere Westmere E56xx/L56xx/X56xx (Nehalem-C)
x86 SandyBridge Intel Xeon E312xx (Sandy Bridge)
x86 IvyBridge Intel Xeon E3-12xx v2 (Ivy Bridge)
x86 Haswell-noTSX Intel Core Processor (Haswell, no TSX)
x86 Haswell Intel Core Processor (Haswell)
x86 Broadwell-noTSX Intel Core Processor (Broadwell, no TSX)
x86 Broadwell Intel Core Processor (Broadwell)
x86 Opteron_G1 AMD Opteron 240 (Gen 1 Class Opteron)
x86 Opteron_G2 AMD Opteron 22xx (Gen 2 Class Opteron)
x86 Opteron_G3 AMD Opteron 23xx (Gen 3 Class Opteron)
x86 Opteron_G4 AMD Opteron 62xx class CPU
x86 Opteron_G5 AMD Opteron 63xx class CPU
x86 host KVM processor with all supported host features (only available in KVM mode)

Recognized CPUID flags:
fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 pn clflush ds acpi mmx fxsr sse sse2 ss ht tm ia64 pbe
pni|sse3 pclmulqdq|pclmuldq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cid fma cx16 xtpr pdcm pcid dca sse4.1|sse4_1 sse4.2|sse4_2 x2apic movbe popcnt tsc-deadline aes xsave osxsave avx f16c rdrand hypervisor
fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f rdseed adx smap pcommit clflushopt clwb avx512pf avx512er avx512cd
syscall nx|xd mmxext fxsr_opt|ffxsr pdpe1gb rdtscp lm|i64 3dnowext 3dnow
lahf_lm cmp_legacy svm extapic cr8legacy abm sse4a misalignsse 3dnowprefetch osvw ibs xop skinit wdt lwp fma4 tce nodeid_msr tbm topoext perfctr_core perfctr_nb
invtsc
xstore xstore-en xcrypt xcrypt-en ace2 ace2-en phe phe-en pmm pmm-en
kvmclock kvm_nopiodelay kvm_mmu kvmclock kvm_asyncpf kvm_steal_time kvm_pv_eoi kvm_pv_unhalt kvmclock-stable-bit
npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pause_filter pfthreshold
xsaveopt xsavec xgetbv1 xsaves
arat
[email protected]:~#

From the preceding output, we can see the list of CPUs that we can pass as parameters to the -cpu flag in order to emulate that CPU type inside our virtual machine.

How to do it...

To start a new virtual machine using the qemu-system utility, perform the following steps:

  1. Start a new QEMU virtual machine using the x86_64 CPU architecture:
[email protected]:~# qemu-system-x86_64 -name debian -vnc 146.20.141.254:0 -cpu Nehalem -m 1024 -drive     format=raw,index=2,file=debian.img -daemonize    
[email protected]:~#
  1. Ensure that the instance is running:
[email protected]:~# pgrep -lfa qemu
3527 qemu-system-x86_64 -name debian -vnc 146.20.141.254:0 -m 1024 -drive format=raw,index=2,file=debian.img -daemonize    
[email protected]:~#
  1. Terminate the Debian QEMU instance:
[email protected]:~# pkill qemu    
[email protected]:~#
  1. Start a new QEMU instance using the prebuilt CentOS image:
[email protected]:~# qemu-system-x86_64 -vnc 146.20.141.254:0 -m 1024 -hda CentOS-7-x86_64-GenericCloud.qcow2 -daemonize    
[email protected]:~#
  1. Ensure that the instance is running:
[email protected]:~# pgrep -lfa qemu
3546 qemu-system-x86_64 -vnc 146.20.141.254:0 -m 1024 -hda CentOS-7-x86_64-GenericCloud.qcow2 -daemonize    
[email protected]:~#
  1. Terminate the CentOS QEMU instance:
[email protected]:~# pkill qemu    
[email protected]:~#

Note

Make sure to replace the IP address of the -vnc parameter with the one from your host machine.

How it works...

How to start a virtual machine with QEMU/KVM depends greatly on the type of image and how the partitions are structured inside that image.

We used two different image types with different partitioning schemes to demonstrate this concept.

In step 1, we used the qemu-system-x86_64 command to emulate a x86_64 CPU architecture, specifically we passed the -cpu Nehalem flag, emulating the Nehalem CPU model. We passed the IP address of our host as a parameter to the -vnc flag. This starts a VNC server in the VM so that we can later use a VNC client to connect to the QEMU instance. We specified the amount of memory to be allocated to the instance, in this case, 1GB with the -m flag. We instructed QEMU that we are going to use a raw image with the format=raw option and the name and location of the actual image with the file=debian.img parameter.

Recall that this raw image contains two partitions with the second partition containing the root filesystem where the bootloader is located. This is very important to remember because we need to specify from what partition index the guest OS should load. We do that with the index=2 flag. Finally, we pass the -daemonize parameter to background the QEMU process.

In step 4, we started another QEMU instance, this time using the qcow2 CentOS image we downloaded earlier. We did not have to specify from what partition we need to boot from this this time because most prebuilt images use the first partition, or only have one partition. We also used the -hda flag instead of the -drive parameter, just to demonstrate that both options can be used with the same result. The -hda flag tells QEMU the first disk for the instance should be loaded from the filename that follows it.

 

Starting the QEMU VM with KVM support


In this recipe, we are going to start a QEMU virtual machine with KVM acceleration. Kernel-based Virtual Machine (KVM) is a full virtualization technology for CPU architectures that support virtualization extensions. For Intel-based processors, this is the Intel VT, and for AMD CPUS, it is the AMD-V hardware extension. The main parts of KVM are two loadable kernel modules, named kvm.ko, which provides the main virtualization functionality, and a second kernel module that is processor specific, kvm-intel.ko and kvm-amd.ko for both main CPU vendors.

QEMU is the userspace component to create virtual machines, where KVM resides in kernel space. If you completed the Running virtual machines with qemu-system-* recipe, you might note that the difference between running a KVM virtual machine and running a nonaccelerated QEMU instance is just a single command-line option.

Getting ready

In order to start a KVM instance, you will need the following:

  • The QEMU binaries, provided after following the Installing and configuring QEMU recipe
  • The custom raw Debian image we built in the Installing a custom OS on the image with debootstrap recipe
  • Processor that supports virtualization
  • The KVM kernel modules

To check whether your CPU supports virtualization, run the following code:

[email protected]:~# cat /proc/cpuinfo | egrep "vmx|svm" | uniq
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm epb tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm xsaveopt cqm_llc cqm_occup_llc dtherm arat pln pts
[email protected]:~#

The presence of the vmx (for Intel) or svm (for AMD) flags indicate that your CPU supports the virtualization extensions.

Note

The flags from the cpuinfo command output simply mean that your processor supports virtualization; however, make sure that this feature is enabled in the BIOS of your system; otherwise, the KVM instance will fail to start.

To manually load the KVM kernel module and ensure that it's been loaded, run the following code:

[email protected]:~# modprobe kvm
[email protected]:~# lsmod | grep kvm
kvm                   455843  0
[email protected]:~#

How to do it...

To start a KVM instance, ensure that it's running and finally terminate it, execute the following:

  1. Start a QEMU instance with KVM support:
[email protected]:~# qemu-system-x86_64 -name debian -vnc 146.20.141.254:0 -m 1024 -drive format=raw,index=2,file=debian.img -enable-kvm -daemonize    
[email protected]:~#
  1. Ensure that the instance is running:
[email protected]:~# pgrep -lfa qemu    
4895 qemu-system-x86_64 -name debian -vnc 146.20.141.254:0 -m 1024 -drive format=raw,index=2,file=debian.img -enable-kvm -daemonize    
[email protected]:~#
  1. Terminate the instance:
[email protected]:~# pkill qemu    
[email protected]:~#

How it works...

To start a QEMU/KVM virtual machine, all we had to do differently from what we performed in the Installing and configuring QEMU recipe is pass the -enable-kvm flag to the qemu-system-x86_64 command.

In step 1, we specified a name for the VM with the -name flag, provided the IP address of our physical host to the -vnc flag, enabling VNC access for the virtual instance, allocated 1 GB of memory with the -m flag, specified the partition where the bootloader is located with the index=2 parameter, the image format, and name, and finally we enabled KVM hardware acceleration with the -enable-kvm parameter and deamonized the process with the -daemonize flag.

In step 2, we ensured that the instance is running and we terminated it in step 3.

There's more...

As an alternative to directly running the qemu-system-* commands, on Ubuntu systems there's the qemu-kvm package that provides the /usr/bin/kvm binary. This file is a wrapper to the qemu-system-x86_64 command, and it passes the -enable-kvm parameter to it automatically.

To install the package and use the kvm command instead, run the following:

[email protected]:~# apt install qemu-kvm
...
[email protected]:~# kvm -name debian -vnc 146.20.141.254:0 -cpu Nehalem -m 1024 -drive format=raw,index=2,file=debian.img -daemonize
[email protected]:~# pgrep -lfa qemu
25343 qemu-system-x86_64 -enable-kvm -name debian -vnc 146.20.141.254:0 -cpu Nehalem -m 1024 -drive format=raw,index=2,file=debian.img -daemonize
[email protected]:~#

You might have noted that starting and stopping QEMU/KVM instances is somewhat of a manual process, especially having to kill the instance process in order to stop it. In Chapter 2, Using libvirt to Manage KVM, we are going to walk you through a set of recipes that will make managing the life cycle of KVM virtual machines much easier, with the userspace tools that the libvirt package provides.

 

Connecting to a running instance with VNC


In this recipe, we are going to connect to a running KVM instance using a VNC client. Once connected, we are going to log in and check the CPU type and available memory of the instance. We've already seen how to start QEMU/KVM instances with VNC support in the previous recipes, but we are going to do it again, in case you are not reading this book from cover to cover.

Virtual Network Computing (VNC) uses the Remote Frame Buffer (RFB) protocol to remotely control another system. It relays the screen from the remote computer back to the client, allowing the full keyboard and mouse control.

There are many different VNC client and server implementations, but for this recipe, we are going to use a freely available version named chicken of the VNC for macOS. You can download the client from https://sourceforge.net/projects/cotvnc/.

Getting ready

In order to complete this recipe, you will need the following:

  • The QEMU binaries, provided after following the Installing and configuring QEMU recipe
  • The custom raw Debian image we built in the Installing a custom OS on the image with debootstrap recipe
  • A processor that supports virtualization
  • The loaded KVM kernel modules
  • The chicken of the VNC client, installed, as described in the previous section

How to do it...

  1. Start a new KVM-accelerated qemu instance:
[email protected]:~# qemu-system-x86_64 -name debian -vnc 146.20.141.254:0 -cpu Nehalem -m 1024 -drive format=raw,index=2,file=debian.img -daemonize    
[email protected]:~#


  1. Ensure that the instance is running:
[email protected]:~# pgrep -lfa qemu    
4987 qemu-system-x86_64 -name debian -vnc 146.20.141.254:0 -cpu Nehalem -m 1024 -drive format=raw,index=2,file=debian.img -daemonize    
[email protected]:~#
  1. Start the VNC client and connect to the VNC server on the IP address and display port you specified in step 1:

The VNC login screen

  1. Log in to the instance using the root user, then check the CPU type and available memory as shown here:

VNC session

How it works...

In step 1, we started a new QEMU instance with KVM acceleration and enabled a VNC server on it with the specified IP address and display port. We specified the amount of available memory and the CPU model name.

In step 4, we logged in the instance using the root user and the password we created when building the image, then obtained the CPU information by running the lscpu command. Note how the CPU model name matches what we specified with the -cpu flag when we started the virtual machine. Next, we checked the allocated memory with the free command, which also matches what we previously specified with the -m parameter.

About the Author

  • Konstantin Ivanov

    Konstantin Ivanov is a Linux Systems Engineer, an open source developer, and a technology blogger who has been designing, configuring, deploying, and administering large-scale, highly available Linux environments for more than 15 years.

    His interests include large distributed systems and task automation, along with solving technical challenges involving multiple technology stacks.

    Konstantin received two Master of Science in Computer Science degrees from universities in Bulgaria and the United States, specializing in System and Network security and Software engineering.

    In his spare time, he loves writing technology blogs and spending time with his two boys.

    Browse publications by this author

Latest Reviews

(3 reviews total)
It has the info I wanted.
dobrý den, stále nám zboží nebylo doručeno, ani nepřišlo žádné oznámení, kdy tak bude učiněno. Můžete nám, prosím, dát vědět, kdy můžeme očekávat zásilku? Děkuji. Memsource a.s.
Concise information. Plenty of real world examples.

Recommended For You

Book Title
Unlock this full book FREE 10 day trial
Start Free Trial