For creating Docker containers from scratch using Nix package manager.
Please, read Domen's introduction to Nix package manager, for more information about Nix.
$ 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.
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