Tuesday, July 15, 2014

Debian packaging with Pbuilder

This post explains how to create chroot environments, for different Debian distributions and system architectures, to build Debian packages. It also includes a description of the packages signing process, so those can later be uploaded to reprepro, an apt-get repository. I decided to write this article as a continuation of the one I wrote explaining how to create Debian packages:


1.- Installing the tools

 apt-get install pbuilder debian-archive-keyring debootstrap devscripts  

2.- Creating the configuration file at /root/.pbuilder

 # Codenames for Debian suites according to their alias. Update these when  
 # needed.  
 # List of Debian suites.  
   "unstable" "testing" "stable")  
 # List of Ubuntu suites. Update these when needed.  
 UBUNTU_SUITES=("saucy" "raring" "precise")  
 # Mirrors to use. Update these to your preferred mirror.  
 # Optionally use the changelog of a package to determine the suite to use if  
 # none set.  
 if [ -z "${DIST}" ] && [ -r "debian/changelog" ]; then  
   DIST=$(dpkg-parsechangelog | awk '/^Distribution: / {print $2}')  
   # Use the unstable suite for certain suite values.  
   if $(echo "experimental UNRELEASED" | grep -q $DIST); then  
 # Optionally set a default distribution if none is used. Note that you can set  
 # your own default (i.e. ${DIST:="unstable"}).  
 #: ${DIST:="$(lsb_release --short --codename)"}  
 : ${DIST:="stable"}  
 # Optionally change Debian release states in $DIST to their names.  
 case "$DIST" in  
 # Optionally set the architecture to the host architecture if none set. Note  
 # that you can set your own default (i.e. ${ARCH:="i386"}).  
 : ${ARCH:="$(dpkg --print-architecture)"}  
 if [ -n "${ARCH}" ]; then  
 # Optionally, set BASEPATH (and not BASETGZ) if using cowbuilder  
 # BASEPATH="/var/cache/pbuilder/$NAME/base.cow/"  
 if $(echo ${DEBIAN_SUITES[@]} | grep -q $DIST); then  
   # Debian configuration  
   COMPONENTS="main contrib non-free"  
   DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}" "--keyring=/usr/share/keyrings/debian-archive-keyring.gpg")  
 elif $(echo ${UBUNTU_SUITES[@]} | grep -q $DIST); then  
   # Ubuntu configuration  
   COMPONENTS="main restricted universe multiverse"  
   DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}" "--keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg")  
   echo "Unknown distribution: $DIST"  
   exit 1  

3.- Creating the chroot environments for different distributions and architectures

For example, to create the chroot for distribution Jessie and architecture i386, we would need to run the following command:
 DIST=jessie ARCH=i386 pbuilder create --mirror ftp://ftp.us.debian.org/debian/ --debootstrapopts "--keyring=/usr/share/keyrings/debian-archive-keyring.gpg"  
The results, as defined in /root/.pbuilder, will be stored at: /var/cache/pbuilder/jessie-i386-base.tgz

Example for Ubuntu:
 DIST=saucy ARCH=i386 pbuilder create --architecture i386 --distribution saucy --debootstrapopts "--keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg"  
Current possible values for DIST are “sid” (unstable), “jessie” (testing), “wheezy” (stable). Other values can be found at /usr/share/debootstrap/scripts/.

Possible values for ARCH are i386 or amd64.

4.- Updating chroot environments (recommended before building the package)

 DIST=jessie ARCH=i386 pbuilder update  
This command will extract the chroot, invoke "apt-get update" and "apt-get dist-upgrade" inside the chroot, and then recreate the base.tgz (in this case jessie-i386-base.tgz).

This is recommended to avoid errors while building the packages. For example when apt-get doesn’t find packages that are used as dependencies.

5.- Building the package inside the chroot environment

From your source code directory, the one that contains the Debian files (in our case /opt/hello-0.1/), run:
 /usr/bin/pdebuild --use-pdebuild-internal --architecture i386 --buildresult /var/cache/pbuilder/jessie-i386/result/ \  
 -- --basetgz /var/cache/pbuilder/jessie-i386-base.tgz --distribution jessie --architecture i386 --aptcache \  
 /var/cache/pbuilder/jessie-i386/aptcache/ --override-config  
The command pdebuild calls dpkg-source to build the source package, and then invokes pbuilder on the resulting source package. Results are stored in the --buildresult directory. 

Pbuilder, which is run as part of pdebuild command, extracts the base.tgz to a temporary working directory, enters the directory with chroot, satisfies the build-dependencies inside the chroot, and builds the package.

According to manual pdebuild should be called this way: 

pdebuild [pdebuild options] -- [pbuilder options]

For more info see:
  • man pdebuild
  • man pbuilder

6.- Generating GPG key and signing package

We need to have a GPG key (can be listed with gpg --list-keys command), or generate a new one, to sign the packages. Then we can sing the package with debsign:
 root@debian-package:/opt# gpg --gen-key  
 pub  2048R/489CD644 2014-07-15  
    Key fingerprint = 39F8 7126 FC58 3272 9A8D 04AB B701 2A82 489C D644  
 uid         Your Name <your_email_address@domain.com>  
 sub  2048R/870B8E2D 2014-07-15  

 root@debian-package:/opt# debsign -k870B8E2D hello_0.1-1_i386.changes   
  signfile hello_0.1-1.dsc 870B8E2D  
 You need a passphrase to unlock the secret key for  
 user: "Your Name <your_email_address@domain.com>"  
 2048-bit RSA key, ID 489CD644, created 2014-07-15  
  signfile hello_0.1-1_i386.changes 870B8E2D  
 You need a passphrase to unlock the secret key for  
 user: "Your Name <your_email_address@domain.com>"  
 2048-bit RSA key, ID 489CD644, created 2014-07-15  
 Successfully signed dsc and changes files  

7.- Testing the Debian package inside the chroot environment

We can easily get access to a shell inside the chroot environment using --login option:
 root@debian-package:/opt# pbuilder --login --basetgz /var/cache/pbuilder/jessie-i386-base.tgz --distribution jessie --architecture i386 --bindmounts "/var/cache/pbuilder/jessie-i386/result" --override-config  
 I: Building the build Environment  
 I: extracting base tarball [/var/cache/pbuilder/jessie-i386-base.tgz]  
 I: creating local configuration  
 I: copying local configuration  
 I: Installing apt-lines  
 I: mounting /proc filesystem  
 I: mounting /dev/pts filesystem  
 I: Mounting /var/cache/pbuilder/jessie-i386/result  
 I: policy-rc.d already exists  
 I: Obtaining the cached apt archive contents  
 I: entering the shell  
 File extracted to: /var/cache/pbuilder/build//27119  


Note: Using --safe-after-login option would save changes in the chroot environment after login out of it.

Now we can go to the results directory, specified with --bindmounts option, and install the package.
 root@debian-package:~# cd /var/cache/pbuilder/jessie-i386/result/  
 root@debian-package:/var/cache/pbuilder/jessie-i386/result# dpkg -i hello_0.1-1_i386.deb  
 Selecting previously unselected package hello.  
 (Reading database ... 12428 files and directories currently installed.)  
 Preparing to unpack hello_0.1-1_i386.deb ...  
 Unpacking hello (0.1-1) ...  
 Setting up hello (0.1-1) ...  
 root@debian-package:/var/cache/pbuilder/jessie-i386/result# hello_world   
 Hello World  
On the other hand, in case other packages are needed as dependencies or for testing, we can run apt-get inside the chroot to install those. As well, more variants and custom packages can be added to debootstrap, as explained here:

8.- References

No comments:

Post a Comment