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.
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.
Some rather outdated statistics: on Collabora's x86-64 build box, the base chroots at one point occupied 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
- Ubuntu dapper i386: 207M
- Ubuntu edgy i386: 196M
- Ubuntu edgy x86-64: 154M
On my laptop I originally allocated 3 GiB for the base system, which should in practice be plenty for an i386-only environment. I now use 5 GiB, since I have plenty of disk.
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 5 GiB in the volume group "vg", naming the resulting LV "/dev/vg/schroot"):
sudo lvcreate -L5G -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
.
If you have a Debian mirror on your LAN, giving it the DNS alias mirror
is
extremely convenient.
cd /mnt
sudo cdebootstrap --flavour=build lenny lenny http://MIRROR/debian
sudo cdebootstrap --flavour=build squeeze squeeze http://MIRROR/debian
sudo cdebootstrap --flavour=build sid sid http://MIRROR/debian
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/chroot.d/NAME
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
if [ $1 = "setup-start" ] || [ $1 = "setup-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" >&2
fi
if [ -e "$EXTRA_APT_SOURCES" ]; then
if [ "$AUTH_VERBOSITY" = "verbose" ]; then
echo "... extra apt sources found" >&2
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" >&2
fi
if [ -e "$APT_PREFS" ]; then
if [ "$AUTH_VERBOSITY" = "verbose" ]; then
echo "... apt preferences found" >&2
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
if [ $1 = "setup-start" ]; then
if : || [ "$AUTH_VERBOSITY" = "verbose" ]; 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
deb-src 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.
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`
Using sbuild
You'll need a bit of extra setup for sbuild: Using sbuild as a Debian maintainer describes how I use it.
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 -c experimental foo-1.2.3.dsc