Ports jail

From bsdtips
Jump to: navigation, search

Back to "Admin building blocks"




Sometimes you want to be able to isolate certain jobs away from the main host environment. Compiling ports with huge dependency lists is a candidate for this. Many times the dependencies involve important foundational packages and effect the proper operation of the host environment. Updating KDE is a good example of this. A full KDE build can take quite some time, even on fast machines, and having a portion of the dependencies updated and a portion outdated can render the desktop partially or fully inoperative. Add to this the possibility of an error (either in the options or a port issue) and you could have to start again in part or full. This is an unacceptable downside for a machine that you want to be operational for continuous use, e.g. your primary desktop. Compiling whole dependency trees in a jail is one solution for this situation (and several other cases).

Optional prerequisites

(or is "Optional prerequisites" an oxymoron?)

Related articles

  • jail_building
  • Ports building options

This article is meant as a follow on to Jail building although I have kept it as applicable to generic jails as possible. Where I use some feature of the Jail building I will note it.


Now we will create and start up a jail with the script from the article Here.

make_jail.sh -D /usr/jails/ports

You will want this jail OS version to match the OS version of your target install machine(s). Additionally, the point of a port builder jail is isolation, this isolation is twofold :

  1. isolate the host from build issues
  2. create pristine packages.

Towards these ends, you should NOT reuse the jail for any other purposes.

Then, get into the jail by finding it's jail ID and jexec-ing yourself a shell.

Host # jls
JID  IP Address              Hostname                Path
  1   YOUR_JAIL_IP_ADDRESS   jail1.example.com       /usr/jails/jail1.example.com/root/  

Host # jexec 1 sh

Update your ports tree like this.

Make the directory that ports will put your buil;t packages in.

Jail1 # mkdir /usr/ports/packages/All

Finally, link the jailed ports tree to the host's environment(1st moving or deleting the old ports tree that was there).

Deleting the old tree :

Host # rm -rf /usr/ports

Moving the old tree :

Host # mv /usr/ports /usr/ports.old

Then link :

Host # ln -s /usr/jails/jail1.example.com/root/usr/ports /usr/ports


Now you can build ports in isolation, installing the resulting packages in the host's environment, in other jails or on other machines. As an example test it out like this :

Host # jexec 1 sh
Jail1 # cd /usr/ports/shells/bash
Jail1 # make package-recursive

You should now have these files in your /usr/ports/packages/All/ (or slightly different version numbers).

Jail1 # pkg_info

These are ready to install with pkg_add.

A real world example

Building something like KDE can take a day (or more) even on a fast machine. While the build process is installing new packages you will have mismatched versions of libs and package for nearly the duration of this process. Here is a simple method to make sure that you have a complete package set built BEFORE you start wholesale upgrading on a machine you may well depend on.

In the host environment, make a text file with all the origins of your packages in it.

Host # pkg_info -o -a -q > /path/to/ports/builder/jail/host_package_list.txt 

Next, for each origin, build a new package in the builder jail.

Host # jexec 1 sh
Jail1 # cat host_package_list.txt | \
Jail1 # while read ORGN
Jail1 # do 
Jail1 #  (cd /usr/ports/$ORGN/ 2> /dev/null && make -DBATCH package || echo "error on ${ORGN}" >> error.log )
Jail1 # done

This process is not bullet proof, if ports move or are restructured massively it has no intelligence built into it to handle it (e.g. the X11 6.X to 7.X "explosion). For work-a-day updates to ports/packages it is however quite effective.

Now in the host environment run pkg_replace (from ports) first setting PKGREPOSITORY and unsetting PACKAGEROOT (to prevent downloading packages)

Host # export PKGREPOSITORY /path/to/ports/builder/jail/usr/ports/packages/All/
Host # export PACKAGEROOT ""
Host # pkg_replace -a -P

If the process missed building a package you can go build it individually and return to the pkg_replace phase again.

Keeping the environment clean

Portupgrade has a useful utility in it, portsclean. Build the package and all dependencies with the target package-recursive for quick addition later via package_add :

Jail1 # cd /usr/ports/ports-mgmt/portupgrade
Jail1 # make package-recursive

The next time all you need to do is (substitute your version number) :

Jail1 # pkg_add /usr/ports/packages/All/portupgrade-2.3.1,2.tbz

Now, to start from a clean ports building environment do this :

Jail1 # portsclean --workclean --distclean
Jail1 # pkg_delete -a


You may want to do a read only nullfs mount into the jails from the port builder like this :

Add this to /etc/fstab :

/usr/jails/ports/live/usr/ports       /usr/jails/[DIRECTORY]/live/usr/ports nullfs ro 0 0


mkdir /usr/jails/[DIRECTORY]/live/usr/ports
mount /usr/jails/[DIRECTORY]/live/usr/ports

Gongo 20:36, 26 September 2007 (UTC)