noteed / nix-build-pack-docker

Nix to Docker buildpack

Repository from Github https://github.comnoteed/nix-build-pack-dockerRepository from Github https://github.comnoteed/nix-build-pack-docker

Nix to Docker buildpack

For creating Docker containers from scratch using Nix package manager.

Please, read Domen's introduction to Nix package manager, for more information about Nix.

Try it

$ git clone https://github.com/datakurre/nix-build-pack-docker
$ cd nix-build-pack-docker
$ make

Then use docker ps (and docker-machine ip default on mac) to figure out, where the example Pyramid service is running.

Step by step

At first, create a generic Nix-builder image and name it nix-builder:

$ docker build -t nix-builder -f nix-builder.docker --rm=true --force-rm=true --no-cache=true .

The builder is made of simple single-user Nix installation on top of some trusted Linux distribution, like debian:

FROM debian:jessie
RUN apt-get update && apt-get install -y curl bzip2 adduser graphviz
RUN adduser --disabled-password --gecos '' user
RUN mkdir -m 0755 /nix && chown user /nix
USER user
ENV USER user
WORKDIR /home/user
RUN curl https://nixos.org/nix/install | sh
VOLUME /nix
COPY nix-builder.sh /home/user/
ENTRYPOINT ["/home/user/nix-builder.sh"]

The image contains a mount point at /nix to support shared persistent Nix-store as a data container for any amount of builder containers.

The entrypoint is a simple script to build a Nix expression and

  • create dependency graph for the build results
  • add /tmp, because that's usually required in images
  • move build results into container root (into /bin etc)
#!/bin/bash
source ~/.nix-profile/etc/profile.d/nix.sh
mkdir tmp
nix-channel --update
nix-build $1
if [ -h result/etc ]; then echo Error: Build resulted /etc as symlink && exit 1; fi
nix-store -q result --graph | sed 's/#ff0000/#ffffff/' | dot -Nstyle=bold -Tpng > $1.png
tar cvz --transform="s|^result/||" tmp `nix-store -qR result` result/* > $1.tar.gz

These build conventions work for me, but the script should be trivial enough to customize.

Note: If the Nix expression results ./result/etc-directory as a symlink (happens when only a single buildInput has ./etc) an error is raised and nothing is created (Docker creates an implict /etc, which cannot be populated from a tarball with /etc as symlink).

Once the builder is build, a data container to persist Nix-store between builds (and allow parallel builds with shared store) is created with:

$ docker create --name nix-store nix-builder

Now you can run the builder for your expression with:

$ docker run --rm --volumes-from=nix-store -v $PWD:/mnt nix-builder /mnt/pyramid.nix

The example pyramid.nix expression simply defines a Python environment with pyramid-package:

with import <nixpkgs> {};

python.buildEnv.override {
  extraLibs = [ pkgs.pythonPackages.pyramid ];
  ignoreCollisions = true;
}

The builder creates a tarball, which could be used in ./Dockerfile to populate an image from scratch:

FROM scratch
ADD pyramid.nix.tar.gz /
EXPOSE 8080
ENTRYPOINT ["/bin/python"]

with a normal docker build command:

$ docker build -t pyramid --rm=true --force-rm=true --no-cache=true .

Finally, the resulting Docker image can be used to Run containers as usual:

$ docker run --rm -v $PWD:/mnt -w /mnt -P pyramid hello_world.py

About

Nix to Docker buildpack


Languages

Language:Makefile 61.4%Language:Python 19.1%Language:Shell 14.3%Language:Nix 5.2%