Tuesday, 5 February 2008

Roll your own N-server sandbox

Have you ever wanted to play around with(test ;) MySQL replication/clustering techniques, LVS/Apache load balancing etc but didn't have the hardware available and where smart enough not to use a production environment?

Well an easy way to be able to do this is by creating a sandbox environment using something like qemu, xen, vmware or UML which allow you to create virtual machines running inside a protected environment on your own desktop machine or whatever hardware you have spare, just be sure you have enough memory. This article will cover setting up a sandbox using UML.

My GNU distro of choice is Archlinux and this article will be based around it, but you should be able to take the information provided here and apply it relatively easily to which ever distro you use. Please also note that I am not going to go into depth about UML as there are plenty of resources just a search away.


Preparing the host.

So first things first we need to have a system capable of running UML, and luckily Archlinux is ready, all we need to do is install a few packages:

[root@ishell ~]# pacman -S user-mode-linux uml_utilities

Then setup our play area. In this example I am setting up a 4 server playground in roots home directory.

[root@ishell ~]# mkdir servers
[root@ishell ~]# cd servers
[root@ishell servers]# mkdir 1 2 3 4
[root@ishell servers]# ls
1 2 3 4
[root@ishell servers]#

Setup the host (the host is the machine "hosting" the UML instances) for networking the UMLs. There are all kinds of ways to do this but I use the uml_switch which is a virtual network switch that is a breeze to use. To allow the UMLs to communicate to and from the host and the outside world we need to create a tunnel and setup IP forwarding (We will start the actual uml_switch at the end in a startup script):

[root@ishell ~]# modprobe tun
[root@ishell ~]# tunctl -u root -t tap0
[root@ishell ~]# ifconfig tap0 192.168.0.100 up
[root@ishell ~]# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
[root@ishell ~]# echo 1 > /proc/sys/net/ipv4/ip_forward


Setup of the UML filesystem

The UML instances require a file to hold their filesystem and a base GNU install. So we create one with dd. As ever salt to your tastes:

[root@ishell servers]# dd if=/dev/zero of=root.fs bs=1MB count=1000
[root@ishell servers]# mkfs.ext3 root.fs

Now we have formatted image we can loopback mount it ready for setting up the base install.

[root@ishell servers]# mount -o loop root.fs /mnt/cd/
[root@ishell servers]# mkdir -p /mnt/cd/var/lib/pacman

To install the base packages with Archlinux I wget the packages.txt from the main package download area which has a list of all base packages prefixed with base/. To install the base packages to the disk image which we have mounted to /mnt/cd we need to first initialize pacman with the -Sy --dbpath options then instruct pacman to install packages to our /mnt/cd root with the --dbpath and --root options. In this case I am also including apache, php, mysql and openssh.


[root@ishell servers]# wget ftp://ftp.archlinux.org/current/os/x86_64/packages.txt
[root@ishell servers]# pacman -Sy --dbpath /mnt/cd/var/lib/pacman
[root@ishell servers]# pacman -S --dbpath /mnt/cd/var/lib/pacman --root /mnt/cd/ \
`cat packages.txt | egrep '^base/' | sed 's|^.*/||;s/-[0-9]\+.*//' | grep -v kernel` \
apache mysql php openssh


Once we have the base install we need to modify some files. These changes apply to all servers we use this image for so it will save us some time if we make the changes now before making copies of the image.

  • add "/dev/ubd0 / ext3 defaults 0 0" to etc/fstab
  • edit /etc/hosts.deny and comment out ALL:ALL so we can gain ssh access
  • edit /etc/innittab and comment out all but the first virtual console
  • add sshd to daemons in rc.conf
  • change default gateway to 192.168.0.100 (or what you set the tunnel IP to)
  • chroot to /mnt/cd and change the root password other wise you will not be able to gain ssh access.

Now umount the image and copy to all servers:

[root@ishell servers]# umount /mnt/cd
[root@ishell servers]# cp root.fs 1/ &
[root@ishell servers]# cp root.fs 2/ &
[root@ishell servers]# cp root.fs 3/ &
[root@ishell servers]# cp root.fs 4/ &

Mount each root image in turn and make configuration changes to the eth0 ip address and hostname in rc.conf, these have to be unique for each server and are the IPs you will use to access the servers via ssh:

[root@ishell servers]# mount -o loop 1/root.fs /mnt/cd/
[root@ishell servers]# nano /mnt/cd/etc/rc.conf
[root@ishell servers]# umount /mnt/cd


And the finishing touch

Create a startup script (i.e. run.sh) and modify the mem parameter to suit your needs. ubd0 specifies the file that contains the filesystem the UML will use and con=null tell the UML not to spawn any consoles or direct any output from the kernel to the console as we will be using ssh as the main form of access, however you can change this if you wish.

The uml_switch is also started here and is passed the name of the tunnel device we setup earlier and told to fork off into a daemon.

#!/bin/bash
exec uml_switch -tap tap0 -daemon &
exec linux ubd0=1/root.fs con=null eth0=daemon mem=128M &
exec linux ubd0=2/root.fs con=null eth0=daemon mem=128M &
exec linux ubd0=3/root.fs con=null eth0=daemon mem=128M &
exec linux ubd0=4/root.fs con=null eth0=daemon mem=128M &


Final thoughts

After running the above script you should have 4 servers ready to go within a few minutes. Simply ssh to them as you would any other server and have fun!

1 comment:

Anonymous said...

GREAT!! It works like a sharm!!!
Thanks, Dino.