Virtualization with KVM
— print (last updated: Jun 20, 2009) print

Select font size:
Personalize this online document by providing values relevant to you. Replace the generic LOGIN by the actual login:
   

Virtualization

The goal of virtualization is to have a software platform on which a completely different instance of an operating system, called a virtual machine, can run. The virtual machine "lives" in a single binary file, called an image file. The system which supports this software is called the host and a virtual machines is called a guest.

The main benefit for us is the ability to set up a "test bed" for trying out software features without tying up extra hardware. One can use this virtualization to install multiple versions of Linux in order to evaluate and compare them. From a security perspective, we can use virtual machines as "attack targets" for security software testing. In an enterprise setting a virtual machine can be a lightweight specialized "server" which is optimized to perform one service task.

There are a number of software tools which serve as the virtualization software including KVM, XEN, VmWare, VirtualBox, etc. Such a software tool is referred to as hypervisor. KVM is only possible if the hardware has sufficient capabilities, but if you can use it, it is extremely fast and Ubuntu supports it well.

KVM considerations

The KVM (Kernel Virtual Machine) software packages is the key component of a set of related software tools which provide full (machine level) virtualization on a machine which has the hardware capabilities to do so. KVM is a spin-off of the QEMU virtual machine software. A significant difference is that KVM can only do full virtualization whereas QEMU can do a slower form when the machine capabilities are not present.

Determination of the requisite hardware on an Intel machine has to do with the appearance of certain processor flags. The processor flags can be found as a line in the /proc/cpuinfo file:
$ cat /proc/cpuinfo | grep ^flags
The test for full virtualization support is the presence of these flags:
vmx             (32-bit machine)
svm             (64-bit machine)
A machine is 64-bit if the "lm" flag appears. Our lab machines are 32-bit. The "positive match" for us means that this command generates output:
$ cat /proc/cpuinfo | grep ^flags | grep vmx

Installation and Creation

Install the necessary packages:
$ sudo apt-get install kvm qemu bridge-utils libvirt-bin \
    ubuntu-vm-builder virt-viewer virt-manager
Included in the installed packages are the MTA (Mail Transfer Agent) postfix which you must configure in 2 screens. First tab to OK, then Enter. Then select No configuration, tab to OK, then Enter.

Create the virtual machine

The inspiration for the steps outlined is the Ubuntu 9.04 Server Guide, chapter 17. In particular, section 2 which describes the minimal JeOS (pronounced "juice") installation using the Ubuntu vmbuilder tool. This is undoubtedly the best approach for creating "production style" virtual machines whose goal is to provide some server function, because it is specifically tuned for the virtual environment and only the minimal number of packages are installed specific to that need.

The terminology used is that the virtual machine is a guest and the real machine is the host. Our first guest will be vm0. It will be "attached" to the virtual bridge interface virbr0, which has been generated for you by the libvirt-bin installation. Check it out by:
$ ifconfig virbr0
Create the folder vm0 in your home directory:
$ mkdir ~/vm0
$ cd ~/vm0
Create the following two files vmbuilder.partition and create_vm0 It's best to simply copy and paste them into the shell.
create_vm0:
vmbuilder kvm ubuntu \
--suite=jaunty \
--flavour=virtual \
--arch=i386 \
--libvirt=qemu:///system \
--hostname=vm0 \
--domain=localdomain \
--part=vmbuilder.partition \
--bridge=virbr0 \
--ip=192.168.122.2 \
--mask=255.255.255.0 \
--user=LOGIN \
--name=Administrator \
--pass=firstpass \
--addpkg=acpid \
--mem=512 \
--tmpfs=- \
-o
vmbuilder.partition:
root 5000
swap 1000
The single terminating "\" characters in create_vm0 are line continuation characters, meaning that the entire file, starting with vmbuilder command, is actually just one line. Here are some points about this vmbuilder command usage:
  1. The kvm argument means to use KVM as the hypervisor.
  2. The "ubuntu --suite=jaunty" combination means to install Ubuntu 9.04 JeOS.
  3. The --libvirt=qemu:///system option indicates to make the virtual machine accessible through the QEMU interfaces. In particular, we can easily control the machine using the virsh command.
  4. The vmbuilder.partition file, introduced through the --part option gives the information for virtual machine's "size", being a 5000MB (5GB) root and 1000MB (1GB) swap, for a total of 6GB.
  5. The RAM size is 512M introduced through the --mem option. This memory usage actually takes away from the memory available to the host machine.
  6. The --bridge=virbr0 option means to use virbr0 as the guest's network interface.
  7. The IP address is 192.168.122.2, defined by the --ip option. The netmask is 255.255.255.0 defined by the --mask option. The last octet, set at 2, can really be anything other than 1. The vmbuilder command recognizes that 192.168.122.1 should be the default IP address for gateway and so there is no need to explicitly set it.
  8. The --user, --name, and --pass set up the initial admin account on the guest.

To create the virtual machine, execute create_vm0 as a bash script:
$ sudo bash ./create_vm0

Access the virtual machine

The guest is most easily accessed through the virsh command. The GUI virt-manager command tool is also useful and interesting.

Start up and access the virtual machine

Once the guest is created, start it by doing:
$ sudo virsh start vm0
Eventually we'll be able to get into the machine through secure shell, but initially we need direct access via:
$ sudo virt-viewer vm0
When you click on the "Virt Viewer" window, note the message at the top, because it's the "way out" of the virtual world. Log in to the virtual machine with the user name and password provided by the vmbuilder command, namely:
vm0 login: LOGIN 
Password: firstpass
Now you're in, so do the things as you would for a "normal" machine:
$ sudo su
# passwd LOGIN 
Enter new UNIX password: the-password-you-really-want
Retype new UNIX password: the-password-you-really-want
We want secure shell to give us more comfortable access to the guest:
# apt-get update
# apt-get install openssh-server
# exit
$ exit
Now close the "Virt Viewer" shell and open a regular shell (in your real machine). Create a host for vm0. Edit the file /etc/hosts. At the end of the file add the entry:
192.168.122.2   vm0
Test ping:
$ ping vm0
Ctrl-C          to stop
Then go in (assuming your login on vm0 should be the same as on your machine):
$ ssh vm0
When you're in you can verify the partitioning and memory allocation by doing:
[vm0] $ sudo fdisk -l /dev/sda
[vm0] $ free
Create a name for the host IP. Edit /etc/hosts in the virtual machine. Use either vim or nano, but first install:
[vm0] $ sudo apt-get install nano vim
[vm0] $ sudo [ nano | vim ] /etc/hosts
Add the line:
192.168.122.1    host
Save, come back to the shell and try these:
[vm0] $ ping host
[vm0] $ ssh host
----------- now you're going into back to your machine from the virtual guest!

Shut down the virtual machine

After you're done, exit the virtual machine's shell. We can use virsh to shut down the machine as well:
$ sudo virsh shutdown vm0

Relevant files and settings

You can see the file which holds guest as:
$ cd ~/vm0
$ ls -s ubuntu-kvm
size-in-K  ...  disk0.qcow2
The "cow" here means copy-on-write. Note that the size in bytes, perhaps around 370K or so, is significantly less than 6GB. The 6GB figure actually represents the maximum size that the virtual machine can be.

The other important configuration files are in the /etc/libvirt directory. See what's there by:
$ ls -lR /etc/libvirt
The bridge network interface, virbr0, is created by the file /etc/libvirt/qemu/networks/default.xml. This bridge network is controlled by the init file /etc/init.d/libvirt.bin. See what's in the network config file by doing:
$ cat /etc/libvirt/qemu/networks/default.xml
In addition, the Ubuntu firewall is configured to use NAT (Network Address Translation) in a way which allows the virtual machine to communicate with the world though the bridge interface. The technique is referred to as masquerading and the arguments used for the iptables firewall operation can be seen by running the command:
$ sudo iptables-save -t nat
revealing the iptables command arguments:
-A POSTROUTING -s 192.168.122.0/24 -d ! 192.168.122.0/24 -j MASQUERADE 
The virtual machine is controlled by the virsh executable through the root-protected config file /etc/libvirt/qemu/vm0.xml. Take a look at its contents:
$ sudo cat /etc/libvirt/qemu/vm0.xml


© Robert M. Kline