<chapter id='chap-build-farm'><title>Setting up a Build Farm</title> <para>This 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: <itemizedlist> <listitem><para>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 <literal>powerpc-darwin</literal> on an <literal>i686-linux</literal> machine, Nix can automatically forward the build to a <literal>powerpc-darwin</literal> machine, if available.</para></listitem> <listitem><para>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.</para></listitem> <listitem><para>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.</para></listitem> <listitem><para>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.</para></listitem> <listitem><para>The results of a Nix build farm can be made available through a channel, so successful builds can be deployed to users immediately.</para></listitem> </itemizedlist> </para> <section><title>Overview</title> <para>TODO</para> <para>The sources of the Nix build farm are at <ulink url='https://svn.cs.uu.nl:12443/repos/trace/release/trunk' />.</para> </section> <section id='sec-distributed-builds'><title>Setting up distributed builds</title> <para>You can enable distributed builds by setting the environment variable <envar>NIX_BUILD_HOOK</envar> 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.</para> <example id='ex-remote-systems'><title>Remote machine configuration: <filename>remote-systems.conf</filename></title> <programlisting> 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 </programlisting> </example> <para>An example build hook can be found in the Nix build farm sources: <ulink url='https://svn.cs.uu.nl:12443/repos/trace/release/trunk/common/distributed/build-remote.pl' />. It should be suitable for most purposes, with maybe some minor adjustments. It uses <command>ssh</command> and <command>rsync</command> 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 <envar>REMOTE_SYSTEMS</envar> to point to it. An example configuration is shown in <xref linkend='ex-remote-systems' />. Each line in the file specifies a machine, with the following bits of information: <orderedlist> <listitem><para>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 <command>ssh</command>, so it can be an alias defined in your <filename>~/.ssh/config</filename>.</para></listitem> <listitem><para>The Nix platform type identifier, such as <literal>powerpc-darwin</literal>.</para></listitem> <listitem><para>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!</para></listitem> <listitem><para>The maximum <quote>load</quote> of the remote machine. This is just the maximum number of jobs that <filename>build-remote.pl</filename> will execute in parallel on the machine. Typically this should be equal to the number of CPUs.</para></listitem> </orderedlist> You should also set up the environment variable <envar>CURRENT_LOAD</envar> to point at a file that <filename>build-remote.pl</filename> 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 <envar>CURRENT_LOAD</envar> file<footnote><para>Although there are probably some race conditions in the script right now.</para></footnote>. Maybe in the future <filename>build-remote.pl</filename> will look at the actual remote load. The load file should exist, so you should just create it as an empty file initially.</para> </section> </chapter>