Skip to main content

building packages with poudriere

Poudriere is a simple way to create FreeBSD binary packages. https://pkg.freebsd.org does this, and those packages are sufficient for most use cases. Building your own packages has some advantages:

  • Work on ports, and have a quick method for testing them
  • Compiling ports at a different frequency than upstream
  • Compiling custom port options that upstream will not take
  • Compiling restricted ports
  • Compiling custom ports trees

Please keep in mind, the version of FreeBSD you want to run poudriere on must match or be greater than the target systems you are building packages for. This is because the jail binaries that are being executed must be compatible with the kernels ABI. I'm building packages for FreeBSD-10.3-RELEASE and FreeBSD-11.0-RELEASE in this example.

Poudriere installation

If you want a more bleeding edge version of poudriere, with newer features try ports-mgmt/poudriere-devel. Otherwise ports-mgmt/poudriere.

Via ports

cd /usr/ports/ports-mgmt/poudriere[-devel] make install

Via pkg

pkg install poudriere[-devel]

Configuration

poudriere.conf

You should go through /usr/local/etc/poudriere.conf and make sure everything in there matches your use case, and suits you. I changed the following options:

ZPOOL=zroot
PKG_REPO_SIGNING_KEY=/usr/local/poudriere/keys/pkg.key

If you want to do signing, leave the PKG_REPO_SIGNING_KEY parameter in the configuration and hit the next section. Otherwise, skip the next section.

Signing

Signing is easy. There isn't any reason you shouldn't do it!

mkdir -p /usr/local/poudriere/keys
chmod 600 /usr/local/poudriere/keys
openssl genrsa -out /usr/local/poudriere/keys/pkg.key 8192
openssl rsa -in /usr/local/poudriere/keys/pkg.key -pubout > /usr/local/poudriere/keys/pkg.cert

Create distfile directory

This is referenced in the poudriere.conf file. mkdir -p /usr/ports/distfiles

Prepare jails

Create a jail for each version of FreeBSD you want to build packages for:

poudriere jail -c -j FreeBSD:10:amd64 -v 11.0-RELEASE -a amd64
poudriere jail -c -j FreeBSD:11:amd64 -v 10.3-RELEASE -a amd64

Prepare ports

poudriere ports -c -p upstream

Building

I wrote this all into a script:

PORTS_TREES='upstream'
JAILS='103-RELEASE 110-RELEASE'
PYTHON_VERSION='3.6'
for PORTS_TREE in ${PORTS_TREES}; do

        # Update poudriere ports tree
        poudriere ports -u -p ${PORTS_TREE}

        for JAIL in $JAILS; do
                MAKEFILE="/usr/local/etc/poudriere.d/${JAIL}-make.conf"
                # Ensure the jail is up to date
                poudriere jail -u -j ${JAIL}

                # Build the ports
                echo "DEFAULT_VERSIONS+= python=${PYTHON_VERSION}" > ${MAKEFILE}
                poudriere bulk -f /usr/local/poudriere/pkg-list.txt -j ${JAIL} -p ${PORTS_TREE}
                rm -f ${MAKEFILE}
        done

done

Just run the script:


Serving built packages

To serve built packages, I'm going to use nginx.

pkg install -y nginx

Simple nginx configuration. Just points the location blocks at the packages and logs. /usr/local/etc/nginx/nginx.conf

load_module /usr/local/libexec/nginx/ngx_mail_module.so;
load_module /usr/local/libexec/nginx/ngx_stream_module.so;

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location /logs {
            alias   /usr/local/poudriere/data/logs/bulk;
            autoindex on;
        }
        location / {
            root   /usr/local/poudriere/data/packages/;
            index  index.html index.htm;
            autoindex on;
        }
    }
}

Enable it at boot time:

sysrc nginx_enable="YES"

Start it on the running system:

service nginx start

You should be able to see your packages by going to your poudriere server in your web browser. If you want to see the logs, simply apend /logs to the end of your URL.

Configuration on target system

I suggest writing the pkg.conf and placing it in the webroot of your nginx server: /usr/local/poudriere/data/packages/pkg.douglas-enterprises.com.conf

# Douglas Enterprises repo configuration 
pkg.douglas-enterprises.com: {
  url: "pkg+http://pkg.douglas-enterprises.com/${ABI}-upstream",
  mirror_type: "srv",
  signature_type: "pubkey",
  pubkey: "/usr/local/etc/pkg/certs/pkg.douglas-enterprises.com.cert",
  enabled: yes
}

I also suggest copying the cert to the webroot for easy fetching:

cp /usr/local/poudriere/keys/pkg.cert /usr/local/poudriere/data/packages/pkg.douglas-enterprises.com.cert

Now installation of this repo is super easy on the target system:

mkdir -p /usr/local/etc/pkg/certs /usr/local/etc/pkg/repos
fetch -o /usr/local/etc/pkg/certs http://pkg.douglas-enterprises.com/pkg.douglas-enterprises.com.cert
fetch -o /usr/local/etc/pkg/repos http://pkg.douglas-enterprises.com/pkg.douglas-enterprises.com.conf
pkg update -f

Automation

Whenever I want to build, I simply run that script. It keeps everything up to date, and is perfect to get added to cron:

0 2 * * * /usr/local/poudriere/run_poudriere.sh

I also checked a few files into a github repo https://github.com/elstevi/poudriere-config and set up an auto deploy mechanism with cron. This allows me to change what packages poudriere is building from anywhere without having to ssh into the machine.