Virtual Machines using KVM on Linux

Using KVM I’ve built a nice Debian system running two Windows Server 2003 machines to help in the transition from Windows to Linux workstations. This is a short log about how it’s set up.

Get the latest version of KVM and install it. Either from source or from your package repository. I’ve built it from source. KVM-27 at the time of writing. Usually make starts to whine about some dependencies. If you don’t know what these are install your distribution’s KVM package.

cd /usr/src/
wget [get the URL from sf.net]
tar zxvf kvm-xx.tar.gz
cd kvm-xx
./configure --prefix=/usr/local/kvm/
make && make install
ln -s  /usr/local/kvm/bin/qemu-system-x86_64 /usr/local/bin/kvm
ln -s /usr/local/kvm/bin/qemu-img /usr/local/bin/kvm-image
depmod -a
modprobe kvm-intel || modprobe kvm-amd

We need to make sure the KVM module is loaded at boot time. Depending on your CPU type add kvm-amd or kvm-intel in /etc/modules.

We have to add a user to run the virtual machines in the standard X session. I’ve used the user virtual with the password virtual. This user will have a minimal X session using openbox.

adduser virtual
su virtual
echo "exec openbox" > ~/.xsession
exit

When you’re using GDM be sure to choose “Run Xclient script” as your X session.

Now let’s make KVM do it’s thing. First we’ve got to configure some stuff to get the network running. We use 802.1d ethernet bridging to bind two or more KVM network tap interfaces together.

brctl addbr br0
ifconfig br0 172.20.0.1 up

We also have to make sure KVM uses this br0 when it starts. Edit /etc/qemu-ifup (and create it if it doesn’t exist) using the following configuration:.

#!/bin/sh
sudo -p "Password for $0:" /sbin/ifconfig $1 0.0.0.0 promisc up
sudo -p "Password for $0:" /usr/sbin/brctl addif br0 $1

Yes, we need sudo. We also need to add virtual to sudoers using the visudo command.

virtual ALL=(root) /usr/local/bin/kvm

Now we’re going to set up KVM itself. Log in as the virtual user in your clean openbox X session and open a terminal window. We will use some shell scripts to get them running because the syntax tends to become a bit complicated. We’ll also create two hard drives for both virtual machines.

mkdir kvm
cd kvm
mkdir 2k3
mkdir 2k3_2
cd 2k3
kvm-image create hd.img 20G
kvm-image create hd2.img 80G
touch start
chmod +x start
cd ../2k3_2
kvm-image create hd.img 20G
kvm-image create hd2.img 80G
touch start
chmod +x start

Edit kvm/2k3/start to contain the following (”virtual” is the password for the virtual user):

#!/bin/sh
echo Uno Momento...
sleep 10
echo "virtual" | sudo -S kvm -localtime -net nic,model=rtl8139,vlan=0,macaddr=52:54:00:12:34:55 -net tap,vlan=0,ifname=tap0 -m 1024 -boot c -usbdevice tablet -hda ~/kvm/2k3/hd.img -hdb ~/kvm/2k3/hd2.img

We sleep for 10 seconds to be sure the kernel is finished loading all the stuff it wanted to load before we start the virtual machine. This was done on a beefy quad-core Xeon machine, so maybe that’s why.

We won’t be using the start script just yet. We need to install Windows first. Put the Windows disc in the drive and use the following command to install Windows on the virtual machine:

echo "virtual" | sudo -S kvm -localtime -net nic,model=rtl8139,vlan=0,macaddr=52:54:00:12:34:55 -net tap,vlan=0,ifname=tap0 -m 1024 -boot d -usbdevice tablet -hda ~/kvm/2k3/hd.img -hdb ~/kvm/2k3/hd2.img -cdrom /dev/cdrom

Let’s do the same for the second machine. We’ll have to change the MAC adrress in order to make these machines talk to each other properly, Edit kvm/2k3_2/start to contain the following:

#!/bin/sh
echo Sex Momentos...
sleep 60
echo "virtual" | sudo -S kvm -localtime -net nic,model=rtl8139,vlan=0 -net tap,vlan=0,ifname=tap1 -m 1024 -boot c -usbdevice tablet -hda ~/kvm/2k3_2/hd.img -hdb ~/kvm/2k3_2/hd2.img

We wait a minute because in this setup the first virtual machine has to be booted first because it’s the domain controller.

Install windows again using the following command:

echo "virtual" | sudo -S kvm -localtime -net nic,model=rtl8139,vlan=0 -net tap,vlan=0,ifname=tap1 -m 1024 -boot d -usbdevice tablet -hda ~/kvm/2k3_2/hd.img -hdb ~/kvm/2k3_2/hd2.img -cdrom /dev/cdrom

But, where’s the MAC address? The default is 52:54:00:12:34:56 so we’ll keep that.

In both virtual machines we’ll have to use fixed IP addressing. 172.20.0.2 on the first and 172.20.0.3 on the second. This is important, you’ll see why a bit later. If this is set the two machines should see each other and the host machine.

Now we put everything together. Add these two lines to ~/.xsession and make sure the file ends with the exec openbox command. Use any terminal emulator you like, I just happen to like aterm.

aterm -e ~/kvm/2k3_2/start &
aterm -e ~/kvm/2k3/start &

Logout and login again. Two Windows virtual machines should boot after their sleep times.

The following bit is optional, but it comes in very handy. I’ve written a quick Bash script to forward some ports to the virtual machines in case the outside world want to talk to the Windows boxes.

cd /usr/local/
wget http://www.wasda.nl/~jorrizza/src/firewall.tar.gz
tar zxvf firewall.tar.gz
rm firewall.tar.gz

Edit /usr/local/firewall/rules/*.rule to your preference and run /usr/local/firewall/update_firewall to apply your changes.
It would be nice to start this script at boot time. So add this command to /etc/rc.local and be sure it’s executable.

Of course this is a pretty minimal setup and you are free to change your own config. This also concludes this little howto. Any questions can be asked in the comment section. Thanks to Dell for the hardware and Syn.acK for the support.

Discussion Area - Leave a Comment