2014. július 29., kedd

Ubuntu: running services inside a chroot

So I got a task the other day: install php 5.5.9 onto a fairly old (10.04.4 LTS "lucid") Ubuntu machine, without breaking the already existing prehistoric php, installed from the default repository.

Also, compiling from the sources was out of question, since my colleges wanted to keep the update procedure as simple as possible.

So how do I install a 14.04.1 LTS "trusty" package onto lucid without wreaking havoc among the packages?

I don't.

First I thought I might install lxc or similar light-weight virtualization solution, but for a single service it seemed to be an overkill. When I saw that the node already using almos all phisical memory alredy, it was completely out of question.

So I decided to build a minimal chroot environment with debootstrap. Unfortunately debootstrap on lucid won't build you a proper (or any) trusty chroot. I tried to install the trusty deboostrap .deb file manually with dpkg, but of course it was unsuccessful. Apparently even the .deb file format is somewhat different between the two versions of the distribution, the package manager never managed to even decompress the archive.

So I just decompressed it on my laptop (running trusty), and compied debootstrap over the lucid machine.

This was a complete waste of time, since the debootstrap script downloaded the .deb files OK, but - guess what - it could not decompress and install them properly. Surprise, surprise.

My last chance was to build the chroot env on my desktop, and use that on the server (fortunately both are amd64).

Here is the debootstrap command I used:

debootstrap --variant=buildd trusty /jails/php559 http://archive.ubuntu.com/ubuntu/

This will download and install a very basic Ubuntu Trusty into /jails/php559.

One quirk is that you need to mount the /proc filesystem before doing any work in the chroot environment:

chroot /jails/php559 mount -t proc proc /proc

After this, you need to install packages like this:

chroot /jails/php559 apt-get install <package name>

As you've probably figured out, running anything inside the new environment can be achieved with

chroot /jails/php559 <command> 

Once you installed anything you needed, you can start / stop services inside the new environment. One thing to note is that those services and applications still use the kernel the node booted, so you can't run too exotic stuff inside a chroot, like a very ancient, or too new software, or software compiled for a different architecture. In those cases you need some kind of virtualization.

One problem remains: how to start service inside a chroot?

I wrote a very skinny init script that resides on the host node's /etc/init.d directory and blindly executes service <program name> <command> inside the chroot:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          jail-php559-apache2
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: apache2 running in jail
# Description:       Start / stop the apache2 instance with php 5.5.9
#                    in an appropriate Trusty chroot jail.
### END INIT INFO

# Author: Fabian Tamas Laszlo 

JAIL=/jails/php559
JAILRUN="chroot $JAIL"
SERVICE=apache2

case "$1" in
  start)
 # Ensure that /proc is mounted inside the chroot
 $JAILRUN mount -t proc proc /proc
 $JAILRUN service apache2 start
 ;;
  *)
 # Delegate any command to service command inside jail
 $JAILRUN service $SERVICE $1
 ;;
esac

Don't forget to run

update-rc.d jail-php559-apache2 defaults

after installing the init script.