Tuesday, April 12, 2016

What is KVM virtualization in Linux?

In the wise words of Wikipedia, "Virtualisation is a broad term that refers to the abstraction of computer resources". Within this definition sits a whole variety of products - Sun's VirtualBox, Parallels, Bochs, Xen, KVM, Qemu, various flavours of VMware and many others. And there's a great deal of jargon to confuse the unwary - emulation, full virtualisation, paravirtualisation, virtual appliance, hypervisor... the list goes on. And not everyone agrees exactly what all these terms actually mean.
We're going to deliberately sidestep the jargon and the hype to take a practical look at the virtualisation technologies in Ubuntu, in particular KVM and Qemu and the related userspace tools that create and manage virtual machines. Although the discussion centres on Ubuntu, the technology is applicable to all Linux distros.
Warning: if you're a little less experienced (or a little more time constrained!) you might find our other article,virtualisation made easy, a little easier to read.
The diagram below is an attempt to show how some of the virtualisation components in Linux relate. The lower part of the diagram shows the underlying technologies. On the left, Xen is a software layer that conceptually sits below the operating system. It's called a hypervisor, and it's the first thing that gets to run (after the bootloader) at boot time. Xen creates a single virtual machine (called Domain 0 or Dom 0 for short) that runs Linux. It's this domain that provides Xen with its virtualised resources. Additional user domains (Called Dom U) can later be created to run additional instances of Linux. Although we won't discuss it further here, Xen is a stable, industrial-strength virtualisation solution. Canonical is using it, for example, to host the virtual Ubuntu machines that students use for hands-on work in their new server course.
Some of the key pieces of the virtualisation jigsaw puzzle, and (approximately) how they fit together, with libvirt right in the middle.
Some of the key pieces of the virtualisation jigsaw puzzle, and (approximately) how they fit together, with libvirt right in the middle.

KVM (not the keyboard switcher)

The middle component of the diagram shows KVM (it stands for Kernel Virtual Machine). KVM provides full virtualisation and can run unmodified Linux or Windows images, but it requires CPU virtualisation extensions (Intel VT or AMD-V). It consists of a loadable kernel module (kvm.ko), that provides the core virtualisation infrastructure, and a processor-specific module (kvm-intel.ko or kvm-amd.ko depending on what processor you have). These kernel components are included in the mainline kernel as from version 2.6.20. KVM is used in conjunction with Qemu to emulate other hardware such as the network card, hard disk, graphics adapter, and so on. It's this combination that we'll focus on here.
On the right of the diagram we see Qemu functioning as a userspace, software-only emulation package. It can be used standalone (that is, it does not require a special kernel module, or CPU virtualisation extensions, or a hypervisor layer) and is capable of running unmodified operating system images. Used standalone, Qemu is not the fastest emulation solution; however, it can be accelerated by using KVM, if it's present, or by the kqemu kernel module.
The top part of the diagram shows a few of the userspace tools. Virsh is a command-line tool for management of virtual machines. It can be used to start, shut down, pause, resume, suspend and restore virtual machines, and to list the currently running machines. It can arrange for VMs to start automatically when the host machine boots, or even to migrate VMs to a different host.
Virt-viewer is a minimal tool for displaying the graphical console of a virtual machine. The console is accessed using the VNC protocol.
Virt-manager is a desktop tool (written in Python) for managing virtual machines. It provides the ability to control the life cycle of existing machines (bootup/shutdown, pause/resume, suspend/restore), provision new virtual machines, manage virtual networks, access the graphical console of virtual machines and view performance statistics.
All of these tools are heavily dependent on libvirt, a C library for interfacing with the underlying virtual machines.Libvirt is the true hero of our story. It provides a stable, consistent API for machine management across a variety of virtualisation technologies. Currently it supports Xen, Qemu, KVM, User Mode Linux and VirtualBox, among others. Libvirt uses XML-based config files under /etc/libvirt and /var/lib/libvirt to define the virtualised hardware. Libvirt is also used by the libvirtd daemon, used to mediate communication with the virtualisation system.

Time for some action

In this tutorial we'll build three KVM-based virtual machines. On the first we'll install Vista from standard installation media. On the second we'll install Red Hat Linux from an ISO image, and the third will install Ubuntu direct from the repositories.
But first, this: KVM requires virtualisation support in your CPU. That is, it requires Intel-VT or AMD-V processor extensions. To see if your processor supports one of these, run the command:
egrep '(vmx|svm)' /proc/cpuinfo
If nothing is shown, your CPU doesn't support hardware virtualisation. Otherwise, it does - but you still need to make sure that virtualisation is enabled in the BIOS.
Now that we've got this caveat out of the way we're going to use virt-manager to build a KVM/Qemu VM running Vista. To begin creating a new VM, right-click on the 'localhost' line in the virt-manager main window and select New from the menu. You'll be taken through a series of information-gathering screens, some of which are shown in the walkthrough, below. The result of this process is an XML file describing the VM's settings (/etc/libvirt/qemu/vista.xml in this case), and a disk image file (/var/lib/libvirt/images/vista) of the VM's filesystem. Virt-manager will automatically boot the newly created VM and begin installation of the operating system from the selected media.

Step by step: Build a virtual Vista install

Choose the source
Choose the source: When you've started the virtual machine creation wizard you'll be asked to choose your installation source. In this case we're installing from a physical Vista DVD.
Make virtual partitions
Make virtual partitions: If you have an ISO image to install from, say so here. Otherwise, use the hosts's CD. The virtual disk can be one of the host's physical partitions, or an image file within the host's filesystem.
Allocate RAM
Allocate RAM: Specify the initial and maximum amount of memory to allocate to the VM, review your choices, then bask in the end product - Vista running within a Qemu/KVM virtual machine.
You can also build VM images from the command line using virt-install. We built our second VM and installed Red Hat from an ISO image with the following command:
$ sudo virt-install --connect qemu:///system --name RHEL5 --ram 1000
 --disk path=/var/lib/libvirt/images/RHEL5.img,size=8 --network network:default
 --accelerate --vnc --cdrom /iso-images/RHEL5.2-x86_64.iso --os-type=linux
The construction of the VM took only seconds, and the Red Hat installer's boot screen came up almost immediately. The system installed and rebooted uneventfully.
For the third VM, and as an alternative to creating an empty virtual machine and then installing an OS into it, we used VMBuilder, a Python script that can construct a VM image from scratch by downloading all the pieces from the Ubuntu repositories on the fly. It's a rewrite of the shell script ubuntu-vm-builder, which was in Ubuntu 8.04 LTS. Both were written by S¿ren Hansen. Here's an example:
$ sudo vmbuilder kvm ubuntu --suite jaunty --flavour virtual --arch i386  -o --libvirt qemu:///system
The only two essential parameters are the first two. Here, kvm specifies the hypervisor (ie the virtualisation technology that the image is intended to work with). Supported values are esxi, xen, kvm, vmw6 and vmserver. The second parameter, ubuntu specifies the distro you want to build; Ubuntu is currently the only one supported.
The time taken to provision a VM in this way will depend heavily on the bandwidth between you and the repositories. If you're planning to install several similar VMs you should consider creating a proxy repository server. This can be as easy as choosing a machine on your network and installing the package apt-proxy:
$ sudo apt-get install apt-proxy
This will create a caching APT proxy that listens on port 9999. You'll need to add a --mirror option to your VMBuilder command line to direct it to the proxy, like this:
--mirror http://server-address:9999/ubuntu
You won't see any speed improvement for the first VM you build, because the proxy will need to populate its cache from the back-end repositories, but subsequent builds should go much faster (on a simple test, the build time for the command shown above dropped from 4 minutes 36 seconds without the proxy to 2m 26s with the proxy).
If you need to build a lot of completely identical machines you should consider using virt-clone. This will copy the disk images of an existing virtual machine and define a new guest with an identical virtual hardware configuration, except that elements that must be unique (such as MAC addresses) will be changed to avoid a clash. For example, we created a clone of our Ubuntu VM in a matter of seconds like this:
$ sudo virt-clone --original ubuntu --name ubuntu3 --file /home/chris/ubuntu-kvm/disk3.qcow2
Cloning from /home/chris/ 100% |=========================| 364 MB    00:03     
VMBuilder accepts around 50 parameters to define the VM's characteristics and to customise the installed software, so you'll almost certainly want to incorporate the command into a shell script so you can tweak it more easily. Some of these parameters are shown in the table below.

Parameters in VMBuilder

ParameterIts meaning in life
--mem=MEMAllocate MEM megabytes of memory to the VM
--rootsize=SIZEAllocate SIZE megabytes to the root partition
--swapsize=SIZEAllocate SIZE megabytes to the swap partition
--ip=ADDRESSSet the IP address
--addpkg=PKGInstall PKG into the VM
--arch=ARCHSpecify the target architecture (AMD64 or i386)
--hostname=NAMESet the hostname to NAME
--mirror=URLFetch packages from the repository at the specified URL
--lang=LANGSet the locale to LANG
--user=USERUsername of the initial user (default is Ubuntu)
--pass=PASSPassword of the initial user (default is Ubuntu)
--libvirt=URIRegister the VM with libvirt at the given URI
By default, VMBuilder creates a fairly minimal system. You can add additional packages through repeated use of the --addpkg option. Using the --firstboot option, you can also specify a script that will run the first time the machine boots; for example, to install the SSH server, so that the key pair generated for it is unique for each machine. If you need to install packages that require user interaction during setup (examples include MySQL and Postfix) you can write an additional script to do this that will run the first time the initial user logs in. This script is specified using the --firstlogin option. These facilities are most likely to be of interest if you're creating an image for a virtual appliance that may be distributed to many users.
As an alternative to running a VMBuilder command with a zillion parameters, you can place the settings into an external configuration file and reference it on the command line something like this:
$ sudo vmbuilder kvm ubuntu -c myconfigfile.cfg
Whichever way you build your VM, you'll end up with two files. The first, in /etc/libvirt/qemu, is an XML file defining the virtual hardware of the machine - its CPU type, how much memory it has, its disks, which network it's connected to, its MAC address and so on. The second file contains the machine's disk image (ie its filesystem). Virt-install and virt-manager create files with the .img extension and put them in /var/lib/libvirt/images, VMBuilder creates files in the QCOW2 format and puts them under your home directory in a directory named after the hypervisor and distro for which they were built. In our example, this directory is called ubuntu-kvm. The 'cow' in the filename stands for Copy On Write. It's a format that can use a read-only base image and store just the differences from the base. This can save lots of disk space if you're creating many virtual machines that share much of their filesystems in common.

Running your VM

Once installed, the VM can be started in several ways. The low-level approach is to run the Qemu emulator directly, simply giving it the VM image file as an argument:
$ sudo kvm /var/lib/libvirt/images/RHEL5.img
This simple command will run the virtual machine using KVM's default machine settings; for example it will have only 128MB of memory, (not the 1000MB we requested when we built it) and it won't have any networking set up. In theory, you can fix all of these things by piling more options on to the KVM command, but it's easier to start the VM using either virt-manager or virsh. These tools read the VM's XML description and then invoke KVM with appropriate options.
Starting the VM from virt-manager is easy. From its main screen, right-click on the desired VM in the list and select Run from the menu.
From virt-manager's main screen you can list your VMs, start or stop them, open a VNC client to view their consoles and examine their CPU and memory usage.
From virt-manager's main screen you can list your VMs, start or stop them, open a VNC client to view their consoles and examine their CPU and memory usage.

Virsh

Then there's virsh. It's surprising that we've got this far without it, because virsh is the Swiss Army knife of virtual machine management. It's basically a wrapper around libvirt and is the command line equivalent of virt-manager. Using virsh I can start my RHEL 5 VM like this:
$ sudo virsh -c qemu:///system start RHEL5
Connecting to uri: qemu:///system
Domain RHEL5 started
(The term 'domain' here really just means 'virtual machine'. It's a term borrowed from Xen, for which libvirt was originally written.) We can now list our running VMs:
$ sudo virsh -c qemu:///system list
Connecting to uri: qemu:///system
 Id Name                 State
----------------------------------
  1 RHEL5                running
Starting the VM this way does not automatically start up the VNC client, so if we want to see the VM's console we'll need to manually fire up the viewer:
$ sudo virt-viewer RHEL5
Using virsh, we can examine the XML definition of a domain (we've deleted some output here for brevity):
$ sudo virsh dumpxml RHEL5

Connecting to uri: qemu:///system
<domain type='kvm' id='1'>
  <name>RHEL5</name>
  <uuid>2cadb958-6533-f728-e86a-421ec96ecfd3</uuid>
  <memory>1024000</memory>
  <os>
    <type arch='x86_64' machine='pc'>hvm</type>
    <boot dev='hd'/>
  </os>
  <devices>
    <emulator>/usr/bin/kvm</emulator>
    <disk type='file' device='disk'>
      <source file='/var/lib/libvirt/images/RHEL5.img'/>
      <target dev='hda' bus='ide'/>
    </disk>
    <disk type='file' device='cdrom'>
      <target dev='hdc' bus='ide'/>
      <readonly/>
    </disk>
    <interface type='network'>
      <mac address='54:52:00:66:7a:66'/>
      <source network='default'/>
      <target dev='vnet0'/>
    </interface>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='5900' autoport='yes' keymap='en-us'/>
  </devices>
</domain>
Alternatively you can directly examine the underlying XML file /etc/libvirt/qemu/RHEL5.xml. This file defines the VM in detail - its name and UUID, how much memory is allocated, which emulator is needed to run it, the location of its filesystem image, which network it's connected to, and much else. Virsh can also be used to:
  • Start, suspend, stop and resume virtual machines.
  • Migrate virtual machines to a different host.
  • Create, destroy list and edit virtual networks.
  • Manage pools of storage to hold VM images.
Altogether, virsh accepts about 90 commands. Running it without arguments invokes an interactive command interpreter mode.

Networking support

Virtual machines need to connect to virtual networks. Libvirt lets you create virtual bridges and other networking hardware and connect it in a variety of topologies. In an out-of-the-box installation, libvirt will create a single network called 'default'. You can see the XML definition of this network using virsh:
$ sudo virsh net-dumpxml default
Connecting to uri: qemu:///system
<network>
  <name>default</name>
  <uuid>a77f2c3f-e951-26c0-4c7d-eb23ace76051</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' forwardDelay='0' />
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254' />
    </dhcp>
  </ip>
</network>
Alternatively, just examine the underlying file directly: it's /var/lib/libvirt/network/default.xml.
This file defines a network called default occupying the IP address block 192.168.122.0/24. The host machine will have a virtual interface connected to this network at 192.168.122.1. A service called dnsmasq listens on this interface to provide DHCP and caching DNS services on this network.

To learn more...

No comments:

Post a Comment