Setting up a Build FarmThis chapter provides some sketchy information on how to set up
a Nix-based build farm. Nix is particularly suited as a basis for a
build farm, since:
Nix supports distributed builds: a local Nix
installation can forward Nix builds to other machines over the
network. This allows multiple builds to be performed in parallel
(thus improving performance), but more in importantly, it allows Nix
to perform multi-platform builds in a semi-transparent way. For
instance, if you perform a build for a
powerpc-darwin on an
i686-linux machine, Nix can automatically forward
the build to a powerpc-darwin machine, if
available.The Nix expression language is ideal for describing
build jobs, plus all their dependencies. For instance, if your
package has some dependency, you don't have to manually install it
on all the machines in the build farm; they will be built
automatically.Proper release management requires that builds (if
deployed) are traceable: it should be possible to figure out from
exactly what sources they were built, in what configuration, etc.;
and it should be possible to reproduce the build, if necessary. Nix
makes this possible since Nix's hashing scheme uniquely identifies
builds, and Nix expressions are self-contained.Nix will only rebuild things that have actually
changed. For instance, if the sources of a component haven't
changed between runs of the build farm, the component won't be
rebuild (unless it was garbage-collected). Also, dependencies
typically don't change very often, so they only need to be built
once.The results of a Nix build farm can be made
available through a channel, so successful builds can be deployed to
users immediately.OverviewTODOThe sources of the Nix build farm are at .Setting up distributed buildsYou can enable distributed builds by setting the environment
variable NIX_BUILD_HOOK to point to a program that Nix
will call whenever it wants to build a derivation. The build hook
(typically a shell or Perl script) can decline the build, in which Nix
will perform it in the usual way if possible, or it can accept it, in
which case it is responsible for somehow getting the inputs of the
build to another machine, doing the build there, and getting the
results back. The details of the build hook protocol are described in
the documentation of the NIX_BUILD_HOOK
variable.Remote machine configuration:
remote-systems.conf
nix@mcflurry.labs.cs.uu.nl powerpc-darwin /home/nix/.ssh/id_quarterpounder_auto 2
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 1
An example build hook can be found in the Nix build farm
sources: . It should be suitable for most purposes, with maybe some minor
adjustments. It uses ssh and
rsync to copy the build inputs and outputs and
perform the remote build. You should define a list of available build
machines and set the environment variable
REMOTE_SYSTEMS to point to it. An example
configuration is shown in . Each
line in the file specifies a machine, with the following bits of
information:
The name of the remote machine, with optionally the
user under which the remote build should be performed. This is
actually passed as an argument to ssh, so it can
be an alias defined in your
~/.ssh/config.The Nix platform type identifier, such as
powerpc-darwin.The SSH private key to be used to log in to the
remote machine. Since builds should be non-interactive, this key
should not have a passphrase!The maximum load of the remote
machine. This is just the maximum number of jobs that
build-remote.pl will execute in parallel on the
machine. Typically this should be equal to the number of
CPUs.
You should also set up the environment variable
CURRENT_LOAD to point at a file that
build-remote.pl uses to remember how many jobs it
is currently executing remotely. It doesn't look at the actual load
on the remote machine, so if you have multiple instances of Nix
running, they should use the same CURRENT_LOAD
fileAlthough there are probably some race conditions
in the script right now.. Maybe in the future
build-remote.pl will look at the actual remote
load. The load file should exist, so you should just create it as an
empty file initially.