Asko Soukka

Nix in Docker – Best of Both Worlds

I’m using Nix mostly on a mac as a development tool, and every now and then I get blocked by some packages not working on OS X.

For those situations I’ve been working for my own Nix image for Docker: A such minimal Docker image that it only contains the files from the Nix installer, but could re-use persistent shared Nix-installation between Docker containers to make itself fast, convenient and lean.

My build recipe is now available at:

Features:

  • A single Docker image, which can be used to run anything from nixpkgs.
  • You can nix-shell -p to get a Docker isolated development shell with all your requirements installed from nixpkgs.
  • You can -v /my/path:/var/nixpkgs to use your own nixpkgs clone.
  • You can -v /my/path:/etc/nix to use your own nix configuration.
  • With the shared data container:
    • Sequential and simultaneous containers can share the same Nix installation.
    • You can nix-env -i to add new commands (or manage custom profiles).
    • You can nix-collect-garbage -d to clean up the data container.
  • You can use it as a base image and add new stuff with nix-env -i.

Bootstrapping

Build a Docker image named nix using the provided Docker based build chain:

$ git clone https://gist.github.com/datakurre/a5d95794ce73c28f6d2f
$ cd a5d95794ce73c28f6d2f
$ make

Create a Docker data container named nix to use a shared persistent /nix for all your Nix containers:

$ docker create --name nix -v /nix nix sh

To know more about where the nix data gets stored with this setup, please, read Docker documentation about managing data in containers.

Examples of use

Running a Python interpreter with some packages:

$ docker run --rm --volumes-from=nix -ti nix \
         nix-shell -p python35Packages.pyramid --run python3

Running a Python Jupyter notebook with mounted context:

$ mkdir .jupyter
$ echo "c.NotebookApp.ip = '*'" > .jupyter/jupyter_notebook_config.py
$ docker run --rm --volumes-from=nix -ti \
         -v $PWD:/mnt -w /mnt -e HOME=/mnt -p 8888 nix \
         nix-shell -p python35Packages.notebook --run "jupyter notebook"

Running a Haskell Jupyter notebook with mounted context:

$ mkdir .jupyter
$ echo "c.NotebookApp.ip = '*'" > .jupyter/jupyter_notebook_config.py
$ docker run --rm --volumes-from=nix -ti \
         -v $PWD:/mnt -w /mnt -e HOME=/mnt -p 8888 nix \
         nix-shell -p ihaskell --run "ihaskell-notebook"

Running development shell for default.nix in mounted context:

Adding --help for nix-commands:

$ docker run --rm --volumes-from=nix nix nix-env -i man
$ docker run --rm --volumes-from=nix nix nix-env --help

Purging nix-store cache:

$ docker run --rm --volumes-from=nix nix nix-collect-garbage -d

Using the image as a base for a new Docker image, with ./Dockerfile:

FROM nix
RUN nix-env -i python
ENTRYPOINT ["/usr/local/bin/python"]
$ docker build -t python --rm=true --force-rm=true --no-cache=true .
$ docker run --rm -ti python