Sometimes you need several virtual machines that are able to communicate with each other and the internet for testing purposes. Today I want to show how this can be achieved on a gentoo linux box using KVM.
Kernel-based Virtual Machine (KVM) is a virtualization solution for the Linux Kernel. It provides the /dev/kvm interface which is used by qemu to emulate guests. KVM can only be used if your CPU supports the Vt-x (Intel) or AMD-V (AMD) extensions. These Extensions enable emulation at almost native speed. Also it is possible to use the vhost-net kernel module to let the network traffic run in its own kernel threads.
Prerequisites
Before we start, I assume that you have a gentoo box up and running. If you do not know how to set up Gentoo Linux you should start with the great documentation. You can check wheather your CPU supports KVM with the following command. If you see the highlighted extension you are all good to start.
1
|
|
Host setup
Kernel setup
As KVM works in kernel space you need to compile the corresponding modules. After invoking menuconfig you need to activate the “Virtualization” category
[*] Virtualization
Also you need to activate support for your cpu and for vhost-net. The following example would fit for an Intel CPU.
[*] Virtualization
--->
<*> Kernel-based Virtual Machine (KVM) support
<*> KVM for Intel processors support
< > KVM for AMD processors support
<M> Host kernel accelerator for virtio net
Finally there are some Kernel modules needed by libvirt
General Setup
--->
[*] Control Group support
--->
[*] Freezer cgroup subsystem
[*] Device controller for cgroups
[*] Group CPU scheduler
[*] Enable perf_event per-cpu per-container group (cgroup) monitoring
[*] Block IO controller
[*] Resource counters
[*] Memory Resource Controller for Control Groups (NEW)
[*] Memory Resource Controller Swap Extension (NEW)
[*] Memory Resource Controller Kernel Memory accounting (EXPERIMENTAL) (NEW)
-*- Networking support
--->
Networking Options
--->
<M> 802.1d Ethernet Bridging
<*> Network priority cgroup
[*] QoS and/or fair queueing
--->
<M> Control Group Classifier
[*] Network packet filtering framework (Netfilter)
--->
<M> Ethernet Bridge tables (ebtables) support
--->
<M> ebt: mark target support (NEW)
Device Drivers
--->
Character devices
--->
-*- Unix98 PTY support
[*] Support multiple instances of devpts
[*] Network device support
--->
-*- Network core driver support
<M> Universal TUN/TAP device driver support
Kernel Hacking
--->
[*] Debug Filesystem
After compiling your brand new kernel your KVM host is ready for the next steps.
QEMU / libvirt setup
The Quick Emulator (QEMU) can work with many virtualization drivers (such as KVM or XEN) or with its own built-in user-space driver. Using QEMU without an accelerator is slow as hell. Luckily we are using KVM, so we can reach almost native speeds. Although QEMU has lots of USE flags, all recommended flags are set by default.
Now we are going to configure libvirt, which is a management tool for various virtualization solutions. It offers us virsh which is a powerful management user interface to control QEMU and our virtual network.
As we want to use the virtual network capabilities and the QEMU support of libvirt, we need to enable the corresponding USE-flag
echo ">=app-emulation/libvirt-1.0.3-r2 virt-network qemu" >> /etc/portage/package.use
We are now ready to install QEMU and libvirt. emerge should output the following
emerge -pv libvirt
These are the packages that would be merged, in order:
Calculating dependencies... done!
[ebuild N ] app-misc/scrub-2.5.2 158 kB
[ebuild N ] net-firewall/ebtables-2.0.10.4 USE="-static" 102 kB
[ebuild N ] sys-apps/dmidecode-2.11 USE="(-selinux)" 54 kB
[ebuild N ] dev-libs/libdaemon-0.14-r1 USE="-doc -examples -static-libs" 333 kB
[ebuild N ] sys-power/pm-quirks-20100619 10 kB
[ebuild N ] sys-libs/libseccomp-1.0.1 USE="-static-libs -tools" 127 kB
[ebuild N ] sys-firmware/sgabios-0.1_pre8 30 kB
[ebuild N ] dev-libs/libaio-0.3.109-r4 USE="(-multilib) -static-libs {-test}" 43 kB
[ebuild N ] sys-devel/bin86-0.16.19 148 kB
[ebuild N ] dev-util/gperf-3.0.4 961 kB
[ebuild N ] net-libs/libssh2-1.4.2 USE="zlib -gcrypt -static-libs {-test}" 665 kB
[ebuild N ] app-text/xhtml1-20020801-r4 227 kB
[ebuild N ] dev-libs/libnl-3.2.22:3 USE="-doc -static-libs -utils" 714 kB
[ebuild N ] dev-libs/nettle-2.6:0/4 USE="gmp -doc -static-libs {-test}" 0 kB
[ebuild N ] dev-lang/swig-2.0.9 USE="pcre -ccache -doc" 5,183 kB
[ebuild N ] sys-firmware/ipxe-1.0.0_p20130225 USE="qemu -iso -undi -usb -vmware" 2,157 kB
[ebuild N ] sys-firmware/seabios-1.7.2.1 USE="binary" 518 kB
[ebuild N ] dev-perl/Text-Unidecode-0.40.0 101 kB
[ebuild N ] dev-perl/libintl-perl-1.200.0 489 kB
[ebuild N ] sys-devel/dev86-0.16.19 697 kB
[ebuild N ] net-dns/libidn-1.26 USE="nls -doc -emacs -java -mono -static-libs" 3,322 kB
[ebuild N ] x11-libs/libpciaccess-0.13.1 USE="zlib -minimal -static-libs" 345 kB
[ebuild N ] sys-libs/libcap-ng-0.6.6 USE="python -static-libs" 359 kB
[ebuild N ] net-dns/dnsmasq-2.66 USE="dhcp ipv6 nls -auth-dns -conntrack -dbus -dhcp-tools -idn -lua -script -tftp" LINGUAS="de -es -fi -fr -id -it -no -pl -pt_BR -ro" 392 kB
[ebuild N ] net-misc/radvd-1.9.2-r1 USE="(-selinux)" 177 kB
[ebuild N ] dev-libs/libtasn1-2.14 USE="-doc -static-libs" 0 kB
[ebuild N ] sys-apps/dbus-1.6.12 USE="-X -debug -doc (-selinux) -static-libs -systemd {-test}" 1,889 kB
[ebuild N ] sys-libs/libcap-2.22 USE="pam" 59 kB
[ebuild N ] sys-firmware/vgabios-0.7a USE="-debug" 1,474 kB
[ebuild N ] dev-perl/Unicode-EastAsianWidth-1.320.0 29 kB
[ebuild N ] net-libs/libtirpc-0.2.2-r1 USE="-kerberos -static-libs" 462 kB
[ebuild N ] net-libs/gnutls-2.12.23-r1 USE="cxx nettle nls zlib -bindist -doc -examples -guile -lzo -pkcs11 -static-libs {-test}" 0 kB
[ebuild N ] app-laptop/radeontool-1.6.3 359 kB
[ebuild N ] app-text/texi2html-5.0-r1 USE="unicode" 15,037 kB
[ebuild N ] app-emulation/qemu-1.4.2 USE="aio caps curl filecaps jpeg ncurses png python seccomp threads uuid vhost-net vnc -accessibility -alsa -bluetooth -debug -fdt -iscsi -mixemu -opengl -pulseaudio -rbd -sasl -sdl (-selinux) -smartcard -spice -static -static-softmmu -static-user -systemtap -tci {-test} -tls -usbredir -vde -virtfs -xattr -xen -xfs" PYTHON_TARGETS="python2_7 -python2_5 -python2_6" QEMU_SOFTMMU_TARGETS="x86_64 -alpha -arm -cris -i386 -lm32 -m68k -microblaze -microblazeel -mips -mips64 -mips64el -mipsel -or32 -ppc -ppc64 -ppcemb -s390x -sh4 -sh4eb -sparc -sparc64 -unicore32 -xtensa -xtensaeb" QEMU_USER_TARGETS="-alpha -arm -armeb -cris -i386 -m68k -microblaze -microblazeel -mips -mipsel -or32 -ppc -ppc64 -ppc64abi32 -s390x -sh4 -sh4eb -sparc -sparc32plus -sparc64 -unicore32 -x86_64" 10,176 kB
[ebuild N ] sys-power/pm-utils-1.4.1-r2 USE="-alsa -debug -ntp" VIDEO_CARDS="intel radeon" 204 kB
[ebuild N ] app-emulation/libvirt-1.0.5.2 USE="caps libvirtd macvtap nls python qemu udev vepa virt-network -audit -avahi -firewalld -fuse -iscsi -lvm -lxc -nfs -numa -openvz -parted -pcap -phyp -policykit -rbd -sasl (-selinux) -systemd -uml -virtualbox -xen" 23,393 kB
If portage complains about netcat blocking netcat6
* Error: The above package list contains packages which cannot be
* installed at the same time on the same system.
(net-analyzer/netcat-110-r9::gentoo, installed) pulled in by
net-analyzer/netcat required by @selected
(net-analyzer/netcat6-1.0-r2::gentoo, ebuild scheduled for merge) pulled in by
>=net-analyzer/netcat6-1.0-r2 required by (app-emulation/libvirt-1.0.5.2::gentoo, ebuild scheduled for merge)
you can solve it this way
emerge -qC netcat && emerge netcat6
This uninstalls netcat and installs netcat6 as a drop in replacement.
After you successfully installed libvirt, you can start it with
/etc/init.d/libvirtd start
Setting up a template VM
As a Gentoo installation can take some time, I prefer to create a template and clone it when I need a new machine. First you need to create a volume for your VM. We use virsh to create it
virsh vol-create-as default Vanilla.img 8192M
This example creates a virtual disk with a size of 8GB, which is sufficient for most installs. If you decide to create smaller disks, you need to take care that you create enough inodes while you create the filesystem. This is important as for example a 3GB disk formatted with the standard ext4 options has not enough inodes for a Gentoo installation.
The next steps depend on wheather you want to use a graphical interface or cli interface.
Using cli
You can start an installation with the following command
virt-install \
--cdrom /var/lib/libvirt/images/install-amd64-minimal-20130725.iso \
-r 1024 \
--accelerate \
-n Vanilla \
--disk /var/lib/libvirt/images/Vanilla.img \
--noautoconsole \
--graphics vnc,listen=0.0.0.0,port=5900 \
-m 00:00:00:00:00:01 \
--os-variant=virtio26
This starts the live image located at /var/lib/libvirt/images/install-amd64-minimal-20130725.iso with 1024MB ram. The machine is accelerated by KVM. The name of the VM is Vanilla and it will use the fresh created image /var/lib/libvirt/images/Vanilla.img which has a size of 8GB. The mac is hardcoded to 00:00:00:00:00:01, so we can use it later for the network configuration and the os type is set to newer linux with virtio enabled. Also a vnc server is launched at port 5900. You can connect to this vnc server with tools like vinage or vnc-viewer.
Using virt-manager
If you are on a desktop machine, you can use virt-manager to setup the VM. The process is straight forward. Just start with a click on new and follow the instructions. You can even connect to a remote libvirt daemon and install your VMs using a graphical interface. To install virt-manager just execute
emerge -av virt-manager
If you have trouble starting the virt-manager you might need to switch your python profile.
host ~ # eselect python list
Available Python interpreters:
[1] python2.7
[2] python3.2 *
host ~ # eselect python set 1
host ~ # eselect python list
Available Python interpreters:
[1] python2.7 *
[2] python3.2
Installation
The Installation process is similar to the one described in the Gentoo handbook with a few differences
-
Kernel Configuation
Processor type and features ---> [*] Paravirtualized guest support ---> [*] KVM paravirtualized clock [*] KVM Guest support Device Drivers ---> Virtio drivers ---> <*> PCI driver for virtio devices [*] Block devices ---> <*> Virtio block driver [*] Network device support ---> <*> Virtio network driver
-
the hdd is mapped to /dev/vda instead of /dev/sda
- the network configuration should be set to dhcp (leave /etc/conf.d/net blank)
Now that we have a working template, we can create a script to automate VM generation.
VM Automation
As I feel most comfortable using perl scripts, the following example is no exception. As I am not using any perl specific libraries this example can be easily adapted to other languages. Note that this script is Gentoo specific (paths etc.) and might not necessarily work on other operating systems.
Note: You need virt-manager to be installed, as virt-clone is part of the package.
clone.pl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
|
network.xml.tt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
To create a new VM you just need to call
/usr/bin/perl clone.pl -n 1
This creates a new VM called VM1 with the mac address 00:00:00:00:00:02. Also it updates the default libvirt network to assign the ip address 192.168.122.2 to this VM. To do so it loads the network.xml.tt template and processes it. Another call to this script creates VM2 with the ip address 192.168.122.3 and so on. The resulting machines can communicate with each other, with the host and with the internet.
Conclusion
Setting up a virtual network with KVM on Gentoo is no rocket science. You just have to enable the necessary kernel modules and install libvirt with the virt-network USE-flag. Most of the other stuff works out of the box and can be easily customized to your special needs and automated.