Testing Debian Package Builds with Docker
Sat, Nov 19, 2016Debian packaging is convoluted and easy to get wrong. When making changes to debian packaging, I find that I want to test new package builds, sometimes on multiple platforms, quickly on my mac.
Rather than cloning my changes to a bunch of physical hosts, I can use docker to quickly set up discardable containers that mimic the target build system.
Some .deb Basics
Build systems generate debian packages in myriad ways, but the basic build command is typically:
dpkg-buildpackage -us -uc
This does a a lot of things, but in a nutshell, it builds the debian package from scratch and deposits it in the project’s parent directory.
The resulting .deb
file can then be inspected in a few ways:
In situ inspection of a .deb. This prints the files that will be installed on the host, but not the pre-and post-installation scripts that will be executed. Use dpkg-deb -c <deb>
.
root@a3635d2302d2:/# dpkg-deb -c tcpdump_4.6.2-5+deb8u1_amd64.deb
drwxr-xr-x root/root 0 2015-08-02 19:33 ./
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/share/
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/share/doc/
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/share/doc/tcpdump/
-rw-r--r-- root/root 4164 2014-07-02 22:12 ./usr/share/doc/tcpdump/README.md.gz
-rw-r--r-- root/root 7706 2015-08-02 19:32 ./usr/share/doc/tcpdump/changelog.Debian.gz
-rw-r--r-- root/root 17555 2014-09-03 01:25 ./usr/share/doc/tcpdump/changelog.gz
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/share/doc/tcpdump/examples/
-rw-r--r-- root/root 567 2014-07-02 22:12 ./usr/share/doc/tcpdump/examples/stime.awk
-rw-r--r-- root/root 1598 2014-07-02 22:12 ./usr/share/doc/tcpdump/examples/send-ack.awk
-rw-r--r-- root/root 1428 2014-07-02 22:12 ./usr/share/doc/tcpdump/examples/packetdat.awk
-rw-r--r-- root/root 529 2014-07-02 22:12 ./usr/share/doc/tcpdump/examples/atime.awk
-rw-r--r-- root/root 6257 2015-05-23 16:22 ./usr/share/doc/tcpdump/copyright
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/share/man/
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/share/man/man8/
-rw-r--r-- root/root 21022 2015-08-02 19:33 ./usr/share/man/man8/tcpdump.8.gz
drwxr-xr-x root/root 0 2015-08-02 19:33 ./usr/sbin/
-rwxr-xr-x root/root 1056376 2015-08-02 19:33 ./usr/sbin/tcpdump
Extraction of .deb contents. This extracts the files that will be installed on the host. Again, this does not include the pre- and post-installation scripts. Use dpkg-deb -x <deb> <target>
.
root@a3635d2302d2:/# dpkg-deb -x tcpdump_4.6.2-5+deb8u1_amd64.deb ~/tcpdump
root@a3635d2302d2:/# tree ~/tcpdump/
/root/tcpdump/
`-- usr
|-- sbin
| `-- tcpdump
`-- share
|-- doc
| `-- tcpdump
| |-- README.md.gz
| |-- changelog.Debian.gz
| |-- changelog.gz
| |-- copyright
| `-- examples
| |-- atime.awk
| |-- packetdat.awk
| |-- send-ack.awk
| `-- stime.awk
`-- man
`-- man8
`-- tcpdump.8.gz
8 directories, 10 files
Extraction of .deb control files, including pre- and post-installation scripts. Use dpkg-deb -e <deb> <target>
.
root@a3635d2302d2:/# dpkg-deb -e python2.7_2.7.9-2+deb8u1_amd64.deb ~/controlfiles/
root@a3635d2302d2:/# tree ~/controlfiles/
/root/controlfiles/
|-- control
|-- md5sums
|-- postinst
|-- postrm
`-- prerm
0 directories, 5 files
Building a .deb with Docker
Let’s say I want to build a debian package on Debian Jessie:
# run from the project root, where debian/control is accessible
docker run --rm -v "$(pwd)":/pkg bunn/debbuild:jessie
This will spin up a Jessie container, install the build-deps listed in debian/control
, and build the package. Afterwards, it will deposit the resulting .deb(s) in your working directory and destroy the build container.
Here’s a similar setup for Ubuntu Precise:
docker run --rm -v "$(pwd)":/pkg bunn/debbuild:precise
Speeding Things Up
Since the base debbuild image doesn’t know what build-deps you might have, you can create a new container that overlays your specific build-deps on top of these packages:
# Example Dockerfile to add systemd and golang build-deps
FROM bunn/debbuild:jessie
RUN apt-get install -y dh-systemd golang
ENV GOPATH /pkg
From here, you can docker build .
and run the resulting image similarly, and it will run the same build script without needing to install the build-deps each time.
Dockerfiles
See https://github.com/mypetyak/debbuild for base dockerfiles and some layering examples.