Saturday, August 3, 2013

Setting up a network buildd with pbuilder, ccache, inoticoming and NFS

I recently bought an N54L HP microserver, which shall act as a build-daemon (buildd) for Debian packaging. The idea of my workflow is the following:

  1. do the maintenance tasks locally, usually using svn-buildpackage, quilt etc.pp
  2. build a source package locally
  3. upload the source to an incoming directory on the server
  4. watch this incoming directory and start a build process as soon as a package is uploaded
  5. put the result into an accessible directory
  6. support different vendors (debian, ubuntu)
  7. support different releases (experimental, unstable, stable, oldstable)
  8. support different architectures (amd64, i386)
  9. speed up the build process

Setting up the building environment

My first idea was to use sbuild as described in several places. However I went with pbuilder for a long time having a setup I personally like. So I decided to stay with it. I reduce the time and work to update the configure files by using

  • one central file /etc/ defining all the common/shared settings and
  • small configure files defining vendor, release, architecture and mirrors

Here are the relevant parts of my central configure snippet:

EXTRAPACKAGES="apt-utils debconf debconf-utils libfile-fcntllock-perl"
case "$VENDOR" in
COMPONENTS="main restricted universe multiverse"
deb $DISTRIBUTION main restricted universe multiverse|\
deb $DISTRIBUTION-updates main restricted universe multiverse|\
deb $DISTRIBUTION-security main restricted universe multiverse|\
COMPONENTS="main contrib non-free"
deb $DISTRIBUTION main contrib non-free|\
DEBBUILDOPTS="-us -uc -j2"

You get the main idea, right? Create own files and directories for each architecture, release and vendor. Further I only want to pull build related packages into the build environment, not into the server environment. So I enabled USE_PDEBUILD_INTERNAL. I don't want to sign anything on the buildd itself and use both cores. That's what DEBBUILDOPTS and AUTO_DEBSIGN are used for. Further I saw some warnings reported during build processes. I therefor install the packages mentioned in EXTRAPACKAGES to every build enviroment. The following are the configure files for the unstable amd64 (default) and the stable i386 build environments:


. /etc/

. /etc/

deb $DISTRIBUTION/updates main contrib non-free|\

Now to not having to update all of these environments manually there is a small parallelized script /usr/local/sbin/update-pbuilder-chroots:


t=$(tempfile -p .upc. -s .list) || exit 1

cat > $t << EOF

parallel /usr/sbin/pbuilder update --override-config --configfile :::: $t | tee -a /var/log/pbuilder.log

rm -f $t

exit 0

The script will make sure, that every change to the configuration file(s) will be considered (--override-config) and is run once a week via cron. The default build environment is updated on a daily base without this restriction:

@reboot root    rm -rf /var/cache/pbuilder/build/*/ >> /dev/null 2>&1
@daily  root    test -x /usr/sbin/pbuilder && /usr/sbin/pbuilder update --configfile /etc/pbuilderrc.amd64.sid | tee -a /var/log/pbuilder.log >> /dev/null 2>&1
@weekly root    test -x /usr/local/sbin/update-pbuilder-chroots && /usr/local/sbin/update-pbuilder-chroots >> /dev/null 2>&1
Speeding up the build process

Sometimes it is necessary to recompile a package. The tool to speed up this process is ccache, which can be easily integrated into pbuilder by setting CCACHEDIR in /etc/ It acts like a cache for compiled files and avoids recompilation in several buildd runs.


It is also possible to use a TMPFS for BUILDPLACE to speed up the build process itself. In this case APTCACHEHARDLINK must be disabled. Well, yeah, I don't do this.

Watch an incoming directory and start the build process

Not much to say about this except that the user nobody is used to run the pbuilder command. Therefor it is necessary to mention this in /etc/sudoers to allow him to do this via sudo command:

nobody          ALL=NOPASSWD:/usr/sbin/pbuilder

The first line is only necessary, if a pbuilder command is started with one of these environmental variables set. This can be useful when e.g. debugging a build failure with a future gcc version that is not yet the default or when debugging a clang build issue or when creating non-stripped binary packages for creating a backtrace (BTW: When there is a common repository of all debugging symbols created?).

Now to start the build process, I created an incoming directory with mods 777 at /var/cache/pbuilder/incoming/ and use inoticoming to watch it. This is started during boot via cron. The following shows the entry for the default unstable amd64 build environment:

@reboot root    /usr/bin/inoticoming --logfile /var/log/inoticoming.log --pid-file /var/run/ /var/cache/pbuilder/incoming --chdir /var/cache/pbuilder/incoming --suffix .dsc --stderr-to-log --stdout-to-log /bin/su -c '/usr/bin/sudo /usr/sbin/pbuilder build --autocleanaptcache {}' nobody \;

Done. That's how the basic buildd works.

Getting the results

The pbuilder BUILDRESULT directory with mods 777 is shared via NFS mount to the workstation. After successfully building the package, debsign and dput can be used as usual.

Setting up the workstation

I use svn-buildpackage for most of my packages. Because pbuilder won't download source tarballs on demand by default (maybe via hook?), the tarball must always be included building the source package, which then gets uploaded via dput to the buildd. This is considered in the command listed in svn-builder in ~/.svn-buildpackage.conf (note, below shows my personal layout):

svn-builder=debuild --post-dpkg-buildpackage-hook=\"dput -f buildd /usr/local/src/packages/$PACKAGE/%p_%s_source.changes\" --no-lintian -d -sa -us -uc -S

The host buildd has been added to ~/

fqdn = mybuildd
login = mylogin
method = scp
incoming = /var/cache/pbuilder/incoming
allow_unsigned_uploads = 1
run_lintian = 0

Done. Now the svn-buildpackage command will create a source package including the source tarball and upload it to the buildd, where the package building starts right after the upload.


This is the main setup which works nicely for the default build environment so far. On the TODO list is to extend this setup so I can easily deal with all the architectures and releases (point 6..8 at the beginning).

Update 17.02.2015

The original article suggested to use the %v variable in the hook to transfer the _sources.changes file to the build-daemon. This will fail if the source version e.g. is X:Y-Z in which case the file created is package_Y-Z_source.changes but the command to execute is:

dput -f buildd package_X:Y-Z_source.changes

and thus will fail. According to dpkg-buildpackage(1) the hook command also accepts a %s variable, which seems to extract the superflous version characters.


  1. Daniel, do you use this for all packages, or just you are personally interested in and/or maintaining? Do you also report finding of the build process and perhaps quality checks via a web page (like the Debian PTS)?

    BTW, after a very long time, I am working on BODR again. Please feel free to check the ChangeLog. I will try to make a BODR 10 release this month; I am now working my way through reports. I'm done with those reported with BODR directly, and now browsing through the Kalzium reports...

    1. Hi Egon, I use it for all packages I build. This can be all packages I maintain, all packages I prepare NMUs for or which I get interested in. ATM I try to stay with those packages I already maintain (ot at least team-maintain).

      About bodr: Saw your work. I'm expecting the new release ... :)