OpenVZ and Asterisk and PAE

This post started out as a simple howto for installing Asterisk in an OpenVZ container on Debian Lenny. It all started out well, as a test box I used my core2duo server running Debian Lenny, did an apt-get of the openvz kernel image that is already in the Lenny standard repository, downloaded an OpenVZ template for  a minimal Lenny virtual machine (VM), got a VM running, installed asterisk using apt-get inside the VM, got it configured, then worked out how to install the zaptel modules (usiing the debian repository’s zaptel-source) in the host machine using module-assistant, and then getting the zaptel stuff recognised within the VM. And it all worked.

However, setting it up on the core2duo box was just a test. I really wanted to set it up on my old Thinkpad T42. It’s been gathering dust since I bought the Macbook, and it seemed such a shame to have it doing nothing. I’ve had an old Thinkpad 600X running Asterisk for a while now. It runs natively (ie. not in a VM) and does the job, but it has a hand compiled kernel and Asterisk … and that kind of set up tends to put me off doing proper updates on it. Hence why I was liking Debian Lenny; modern kernel and Asterisk 1.4.x in the standard repository. And the T42 had a bit of horsepower with a 1GB of RAM and a 100GB drive, so I thought something like Asterisk could be virtualised on it.

So step 1, install Lenny from CD on the T42 and ‘apt-get update’ , ‘apt-get upgrade’, then step 2 ; install the openvz kernel image;

apt-get install linux-image-2.6.26-1-openvz-686

And reboot … and nothing. It would not boot. Obviously my Thinkpad did not like this kernel. It turns out that the Debian Lenny OpenVZ kernel is compiled with PAE support compiled in. A core2duo has PAE support. The Pentium M in the Thinkpad does not support PAE.

So what to do? I could go on about the other virtualisation techniques I tried here … but ultimately I liked the idea of OpenVZ; Simple kernel mod, light overhead, don’t need dedicated raw files on disk for VMs. I also liked that Lenny had a standard OpenVZ kernel in it’s repository, which ultimately meant ‘easy kernel updates’.

So I thought I’d have  a go at trying to recompile the Debian OpenVZ kernel with PAE turned off … in a supportable way. To me the easy way is to get a vanilla kernel from kernel.org, and add the patches from openvz.org. But I wanted to have a kernel closely approximating the latest apt-get’able Debian OpenVZ kernel.

I’ve used make-kpkg to make my own debian kernels before, but that didn’t really work in this case.

So here’s what I did (I got a lot of ideas from this post about Xen without PAE);

# get the source
cd /usr/src
apt-get source linux-image-2.6.26-1-openvz-686

Now you should end up with a /usr/src/linux-2.6-2.6.26 directory. It looks like a normal kernel extraction directory, but with a debian directory.

cd /usr/src/linux-2.6-2.6.26/debian/config/i386
vi config.686-bigmem

Now I just searched for PAE in the partial config file and turned it off, as well as disabled the 64GB setting and enabled the 4GB one. Mine looks like this:

CONFIG_HIGHMEM4G=y
CONFIG_HIGHMEM64G=n
## end choice
CONFIG_X86_PAE=n

Save that. Now do all the steps to apply patches, build the config, and compile to generate the kernel image and headers deb

cd /usr/src/linux-2.6-2.6.26
fakeroot debian/rules debian/build debian/stamps

# Removing these ABI files below is a cheap hack workaround to errors that are normally produced at the end of the compile

rm debian/abi/2.6.26-1/*
fakeroot make -f debian/rules.gen binary-arch_i386_openvz_686

That last fakeroot command will take ten bazillion years to complete. Once complete you should end up with two deb files in /usr/src;

linux-headers-2.6.26-1-openvz-686_2.6.26-13_i386.deb
linux-image-2.6.26-1-openvz-686_2.6.26-13_i386.deb

Now install both of these;

cd /usr/src
dpkg -i linux-headers-2.6.26-1-openvz-686_2.6.26-13_i386.deb
dpkg -i linux-image-2.6.26-1-openvz-686_2.6.26-13_i386.deb

And make sure you have the OpenVZ tools installed;

apt-get install vzctl

And try rebooting

This time it worked for me.

And now (finally) we set up a virtual machine and install Asterisk in it.

Download an OpenVZ template for Lenny from http://openvz.org/download/template/cache;

debian-5.0-i386-minimal.tar.gz

You just put the tar.gz file in /var/lib/vz/template/cache (ie. don’t extract it).

Then its a case of picking a unique id for your VM (eg. 101) and doing  something like;

vzctl create 101 –ostemplate debian-5.0-i386-minimal –config vps.basic
vzctl set 101 –onboot yes –save
vzctl set 101 –hostname testmachine –save
vzctl set 101 –ipadd 10.1.2.3 –save
vzctl set 101 –nameserver 1.2.3.4 –save
vzctl start 101

The VM should start quickly and to get a sort of console you enter;

vzctl enter 101

One thing that confused me initially is how networking works. The basic example above uses venet networking. I wasnt sure whether the IP address I specified should be on a seperate subnet or on the same subnet as my host machine. In the end, I used an IP address that was on the same subnet as my host machine. It doesn’t use brctl style bridging, but it effectively bridges the interface onto your network. I must admit I couldn’t find a decent explanation/diagram of how OpenVZ networking works.

Install asterisk in the VM;

apt-get install asterisk

The install worked fine, but because of problems with Music On Hold in the past I wanted to set up ztdummy properly. This can be done.

In the host machine I installed the zaptel modules per this debian howto

apt-get install zaptel-source
module-assistant prepare
module-assistant auto-install zaptel

Afer you do that, do a ‘modprobe ztdummy’. The first time I tried this it didn’t work, because Lenny had downloaded the ‘official’ package for the OpenVZ kernel headers rather than the one that I generated. If that happens to you, dpkg -r the old package, and then install the headers deb that you created earlier. Then run the auto-install above again and double check that the ztdummy modules inserts cleanly. If you do a dmesg now, you should see something like;

ztdummy: High resolution Timer started, good to go

So that gets ztdummy working from the host machine. We need to make it accessible from within the virtual machine. I looked at the following two howtos;

http://wiki.openvz.org/Asterisk_in_VE_with_debian_stable
http://wiki.openvz.org/Asterisk_from_source (I just used the vzctl example commands they have)

The big test of whether the ztdummy stuff is working from inside the virtual machine is to run zttest and hit ctrl-c after a few lines of output. Here’s how mine runs;

root@lenny:/# zttest
Opened pseudo zap interface, measuring accuracy…
99.996582% 99.975983% 99.984177% 99.983887% 99.984070% 99.984467% 99.984375%
99.984177% 99.979492% 99.984467% 99.981735% 99.983208% 99.984581% 99.982819% 99.983978%
99.982811% 99.977448% 99.983971% 99.983971% ^C
— Results after 19 passes —
Best: 99.997 — Worst: 99.976 — Average: 99.983484, Difference: 99.983484

So the only bit remaining for me was to configure asterisk. I just copied files over from my old Asterisk server and got it going. The only issues I had;

  • I found I had to change the asterisk.conf file so that it had the following change;astdatadir => /usr/share/asterisk
    Debian seems to put all the sounds and music on hold data under /usr/share/asterisk (instead of /var/lib/asterisk). I had some ulaw and g729 sounds on the old server, so I copied those into /usr/share/asterisk/sounds

And that is pretty much it. What an endeavour. In hindsight, if I had counted the cost of all the effort put in to get this working on a non-PAE CPU, it would have been easier to just buy a newer system with a PAE CPU.

UPDATE: I used the simple venet networking when I initially set up the Asterisk virtual machine. Unfortunately, the VM would work for a few hours and then either lose its default route or be unable to get responses to DNS requests … so I ended up converting the VM to veth networking using the notes here and here. It now works much better.

UPDATE: I noticed after doing this, that an apt-get update/upgrade may end up trying to download a kernel with the same name as the one I compiled. There should be a way around this, but for now I’m doing the following to prevent my kernel and headers being overwritten (NB: You may have to undo the change below in order to install a new self-compiled kernel. You probably just need to change ‘hold’ to ‘install’ to undo the change below);

# echo “linux-headers-2.6.26-1-openvz-686 hold” | dpkg –set-selections
# echo “linux-image-2.6.26-1-openvz-686 hold” |dpkg –set-selections

UPDATE: I had problems with DNS lookups occasionally hanging from within the OpenVZ virtual machine. If I did a ‘cat /proc/user_beancounters’ from inside the virtual machine, the failcnt column would have a non-zero number against the dgramrcvbuf.  Apparently this has something to do with udp buffers. As a quick workaround I did this to double the barrier limit for that parameter;

sudo vzctl set 102 --dgramrcvbuf $((262144*2)) --save