My setup for schroot and sbuild is based on an idea I saw on Planet Debian a while ago. (Sorry, I can't remember whose idea it was, and I can't find it with Google - if I've stolen your idea, please let me know and I'll give you proper credit!)
Instead of having persistent chroot environments which can get broken by buggy package builds, I maintain several clean chroot environments on an LVM volume. schroot sets up snapshots of that volume for normal use; it's also possible to use the underlying "source" volume, mainly to upgrade it.
I use this configuration on Collabora's build box, and also on my laptop.
[Updated 2007-12-10: better instructions for making chroots, avoiding Recommends being installed]
[Updated 2008-04-13: updated hook scripts to the ones I actually use. Search for "2008-04-13". See also: Using sbuild as a Debian maintainer]
The naive thing to do would be to allocate a logical volume for each chroot. However, each LV needs enough space to hold a minimal base system, plus the largest package build you ever want to do (including its build dependencies), since the snapshot used for the actual build can't get bigger than the base LV.
So, you can actually minimize the space requirements by putting all the base systems on the same LV - then this LV needs enough space for all the base systems combined, plus the largest package build you'll do. Allow 200-250 MiB per base chroot, so if you want to support Debian stable, testing and unstable and Ubuntu LTS, current and current+1, you'll need 1.5 GiB plus the space for the build - double that if you want x86-64.
However, if you have a build environment which is basically the same as another, you can share the base system using some schroot hooks I describe later. For instance, I don't have a base for Debian experimental - I just construct it as needed, by upgrading from unstable.
On Collabora's x86-64 build box the base chroots currently occupy 1.6 GiB of a 5 GiB LV, with the following sizes (just after an apt-get clean):
- Debian etch i386: 213M
- Debian etch x86-64: 216M
- Debian sid i386: 216M
- Debian sid x86-64: 221M
and for Ubuntu builds:
- Ubuntu dapper i386: 207M
- Ubuntu edgy i386: 196M
- Ubuntu edgy x86-64: 154M
On my laptop I allocated 3 GiB for the base system, which should in practice be plenty for an i386-only environment.
You'll also need some free space in the same volume group - the maximum you can theoretically need is the free space on your base LV, plus the size of the largest base system, all multiplied by the number of simultaneous builds you'll do. This is to allocate snapshot LVs in. In practice you can get away with rather less than that.
Setting up the logical volumes
Having decided how much space you want in the base, set up an LV for your base system (here I use 3 GiB in the volume group "vg", naming the resulting LV "/dev/vg/schroot"):
sudo lvcreate -L3G -nschroot vg
format it:
sudo mkfs.ext3 -Lschroot /dev/vg/schroot
and temporarily mount it somewhere so you can create the base systems:
sudo mount /dev/vg/schroot /mnt
Setting up Debian base systems with cdebootstrap
cdebootstrap is part of the Debian installer. Replace MIRROR with your local Debian mirror.
For use on a laptop with potentially wobbly networking, you probably want to cache installed packages with a local instance of approx, in which case replace MIRROR with localhost:9999.
cd /mnt sudo cdebootstrap --flavour=build sarge sarge http://MIRROR/debian sudo cdebootstrap --flavour=build etch etch http://MIRROR/debian sudo cdebootstrap --flavour=build sid sid http://MIRROR/debian
Setting up Ubuntu or Debian base systems with debootstrap
debootstrap was the shell script that inspired cdebootstrap. It's likely to be more fragile, but the version shipped in Ubuntu supports making Ubuntu as well as Debian chroots, which cdebootstrap doesn't.
As an alternative to the cdebootstrap commands above, you could use:
cd /mnt sudo debootstrap --variant=buildd sarge sarge http://MIRROR/debian sudo debootstrap --variant=buildd etch etch http://MIRROR/debian sudo debootstrap --variant=buildd sid sid http://MIRROR/debian
To get Ubuntu chroots on a Debian system, you'll have to fetch the debootstrap source tarball from <http://packages.ubuntu.com/debootstrap>. Untar it somewhere (I used ~/tmp) and use:
cd /mnt
sudo debootstrap dapper dapper http://MIRROR/ubuntu \
~/tmp/debootstrap-0.3.3.2ubuntu3/dapper
sudo debootstrap edgy edgy http://MIRROR/ubuntu \
~/tmp/debootstrap-0.3.3.2ubuntu3/edgy
sudo debootstrap feisty feisty http://MIRROR/ubuntu \
~/tmp/debootstrap-0.3.3.2ubuntu3/feisty
Very basic chroot configuration
At this point you want to set up the absolute basics in each schroot: /etc/resolv.conf, /etc/hosts and possibly /etc/sudoers.
In distributions where Recommends are installed by default, you probably also want to put this in /etc/apt/apt.conf:
APT::Install-Recommends "false";
If you'll be using the chroot for development rather than just builds, you'll probably want to add a deb-src line to /etc/apt/sources.list.
After that, unmount /mnt before continuing.
Configuring schroot
Here's what to put in /etc/schroot/schroot.conf for each chroot:
[sid] # Optional. The chroot with alias 'default' is used if you just type # 'schroot' without the -c option. aliases=unstable,default # Whatever you like description=Debian sid # Relative to what was /mnt until a moment ago location=/sid # Below here is standard for all the chroots # Adjust according to the space available and size of builds you'll do lvm-snapshot-options=--size 2G device=/dev/vg/schroot type=lvm-snapshot priority=3 groups=sbuild,root root-groups=sbuild,root source-groups=sbuild,root source-root-groups=root run-setup-scripts=true run-exec-scripts=true # if you used XFS, you'll also need: #mount-options=-o nouuid
If you want more than one chroot sharing a base system, make the name in square brackets different, but keep the location the same. For instance, my experimental chroot is headed [experimental] but uses location=/sid.
If most of your builds will be quite small, but you occasionally do one that needs more space, it may be worthwhile setting the snapshot size to be quite small, but then adding chroots like [sid-large] that use a larger snapshot for the same base system.
The schroot.conf from my laptop 'carbon' is available as an example.
Adding hooks
Put this in /etc/schroot/setup.d/60append-apt-sources:
#!/bin/sh
# /etc/schroot/setup.d/60append-apt-sources
# Updated 2008-04-13 to support replacing /etc/apt/preferences
if [ "z$1" = "zsetup-start" ] || [ "z$1" = "zsetup-recover" ]; then
NAME=$(echo "${CHROOT_NAME}" | sed -e 's/-[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]//g')
EXTRA_APT_SOURCES="/etc/schroot/sources.list.d/${NAME}.sources.list"
APT_PREFS="/etc/schroot/sources.list.d/${NAME}.preferences"
if [ "$AUTH_VERBOSITY" = "verbose" ]; then
echo "Checking for auxiliary apt sources in $EXTRA_APT_SOURCES"
fi
if [ -e "$EXTRA_APT_SOURCES" ]; then
if [ "$AUTH_VERBOSITY" = "verbose" ]; then
echo "... extra apt sources found"
fi
cat "$EXTRA_APT_SOURCES" >> "${CHROOT_PATH}/etc/apt/sources.list"
fi
if [ "$AUTH_VERBOSITY" = "verbose" ]; then
echo "Checking for apt preferences in $APT_PREFS"
fi
if [ -e "$APT_PREFS" ]; then
if [ "$AUTH_VERBOSITY" = "verbose" ]; then
echo "... apt preferences found"
fi
install -m644 "$APT_PREFS" "${CHROOT_PATH}/etc/apt/preferences"
fi
fi
and this in /etc/schroot/setup.d/80apt-get-update:
#!/bin/sh
# /etc/schroot/setup.d/80apt-get-update
# Updated 2008-04-13 to never output to stdout
if [ "z$1" = "zsetup-start" ]; then
if [ "z$AUTH_VERBOSITY" = "zverbose" ]; then
chroot "${CHROOT_PATH}" apt-get update >&2 || true
else
chroot "${CHROOT_PATH}" apt-get update >/dev/null || true
fi
fi
chmod them both to be executable.
Using the sources.list hook
Create a directory /etc/schroot/sources.list.d and place files in it named after a chroot, with .sources.list appended. For instance, in /etc/schroot/sources.list.d/experimental.sources.list write:
# /etc/schroot/sources.list.d/experimental.sources.list deb http://MIRROR/debian experimental main
with MIRROR replaced as above. Now that sources.list fragment will be appended to /etc/apt/sources.list in [experimental] chroots only. apt's default pinning behaviour means the experimental packages will only be used where selected by a versioned dependency.
If you want to force in experimental versions of particular packages, you can also do so with a file like this:
# /etc/schroot/sources.list.d/experimental.preferences Package: libdbus-glib-1-dev Pin: release a=experimental Pin-Priority: 990 Package: libdbus-glib-1 Pin: release a=experimental Pin-Priority: 990
Entering the source chroots
You can enter the source chroots with a command like:
schroot -c sid-source
Typically you'll want to do this as root, to perform updates or set up configuration. Some things you probably want to do on each chroot to start with:
outside% sudo schroot -c sid-source
inside# apt-get upgrade
inside# apt-get install devscripts vim-tiny sudo fakeroot aptitude \
build-essential
inside# apt-get clean
Changes made here will be reflected in all subsequent snapshots.
For Sarge, or if you want a more capable editor in the chroot, install vim instead of vim-tiny.
Entering a snapshot
Enter a snapshot with a command like:
schroot -c sid
Any changes you make will be lost after the snapshot is closed.
Build a package in a single-use snapshot with:
sbuild foo-1.2.3.dsc
or to override the distribution in the .dsc file,
sbuild -d experimental foo-1.2.3.dsc
(Note that the distribution from sbuild -d will go into the .changes file. I've filed Debian bug #474160 asking for the ability to change the chroot independently.)
Create a persistent snapshot with:
schroot --begin-session -c sid > my-sid-session-id
You can then resume it with:
schroot --run-session -c `cat my-sid-session-id`
and end it with:
schroot --end-session -c `cat my-sid-session-id`