From df589a438e01c06a6661cbd18bfe8f568d8b7f83 Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Fri, 25 Aug 2017 11:47:28 +0200 Subject: [PATCH 1/2] dockerTools.buildImageWithNixDb: populate the Nix Db of the image Nix store Currently, the contents closure is copied to the layer but there is no nix database initialization. If pkgs.nix is added in the contents, nix-store doesn't work because there is no nix database. From the contents of the layer, this commit generates and loads the database in the nix store of the container. This only works if there is no parent layer that already have a nix store (to support several nix layers, we would have to merge nix databases of parent layers). We also add an example to play with the nix store inside the container. Note it seems `more` is a missing dependency of the nix package! --- pkgs/build-support/docker/default.nix | 32 +++++++++++++++++++++++++- pkgs/build-support/docker/examples.nix | 17 ++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index 8a7b362bd5e..cfd2c8a31f9 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -10,6 +10,8 @@ lib, pkgs, pigz, + nixUnstable, + perl, runCommand, rsync, shadow, @@ -27,7 +29,7 @@ rec { examples = import ./examples.nix { - inherit pkgs buildImage pullImage shadowSetup; + inherit pkgs buildImage pullImage shadowSetup buildImageWithNixDb; }; pullImage = @@ -239,6 +241,17 @@ rec { ${text} ''; + nixRegistration = contents: runCommand "nix-registration" { + buildInputs = [ nixUnstable perl ]; + # For obtaining the closure of `contents'. + exportReferencesGraph = + let contentsList = if builtins.isList contents then contents else [ contents ]; + in map (x: [("closure-" + baseNameOf x) x]) contentsList; + } + '' + printRegistration=1 perl ${pkgs.pathsFromGraph} closure-* > $out + ''; + # Create a "layer" (set of files). mkPureLayer = { # Name of the layer @@ -544,4 +557,21 @@ rec { in result; + + # Build an image and populate its nix database with the provided + # contents. The main purpose is to be able to use nix commands in + # the container. + # Be careful since this doesn't work well with multilayer. + buildImageWithNixDb = args@{ contents ? null, extraCommands ? "", ... }: + buildImage (args // { + extraCommands = '' + echo "Generating the nix database..." + echo "Warning: only the database of the deepest Nix layer is loaded." + echo " If you want to use nix commands in the container, it would" + echo " be better to only have one layer that contains a nix store." + # This requires Nix 1.12 or higher + export NIX_REMOTE=local?root=$PWD + ${nixUnstable}/bin/nix-store --load-db < ${nixRegistration contents} + '' + extraCommands; + }); } diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix index aead53f6f7d..1a8b9c7f8ed 100644 --- a/pkgs/build-support/docker/examples.nix +++ b/pkgs/build-support/docker/examples.nix @@ -7,7 +7,7 @@ # $ nix-build '' -A dockerTools.examples.redis # $ docker load < result -{ pkgs, buildImage, pullImage, shadowSetup }: +{ pkgs, buildImage, pullImage, shadowSetup, buildImageWithNixDb }: rec { # 1. basic example @@ -83,7 +83,7 @@ rec { }; # 4. example of pulling an image. could be used as a base for other images - nix = pullImage { + nixFromDockerHub = pullImage { imageName = "nixos/nix"; imageTag = "1.11"; # this hash will need change if the tag is updated at docker hub @@ -101,4 +101,17 @@ rec { pkgs.nano ]; }; + + # 5. nix example to play with the container nix store + # docker run -it --rm nix nix-store -qR $(nix-build '' -A nix) + nix = buildImageWithNixDb { + name = "nix"; + contents = [ + # nix-store -qR uses the 'more' program which is not included in + # the pkgs.nix dependencies. We then have to manually get it + # from the 'eject' package:/ + pkgs.eject + pkgs.nix + ]; + }; } From cb6fc52f998f8f3106a1506c052cffae752e8b7c Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Wed, 13 Sep 2017 11:40:26 +0200 Subject: [PATCH 2/2] dockerTools.buildImageWithNixDb: Make output paths valid and add gcroots The database dump doesn't contain sha and size. This leads to invalid path in the container. We have to fix the database by using nix-store. Note a better way to do this is available in Nix 1.12 (since the database dump contains all required information). We also add content output paths in the gcroots since they ca be used by the container. --- pkgs/build-support/docker/default.nix | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index cfd2c8a31f9..267a2812a2a 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -249,7 +249,9 @@ rec { in map (x: [("closure-" + baseNameOf x) x]) contentsList; } '' - printRegistration=1 perl ${pkgs.pathsFromGraph} closure-* > $out + mkdir $out + printRegistration=1 perl ${pkgs.pathsFromGraph} closure-* > $out/db.dump + perl ${pkgs.pathsFromGraph} closure-* > $out/storePaths ''; # Create a "layer" (set of files). @@ -571,7 +573,23 @@ rec { echo " be better to only have one layer that contains a nix store." # This requires Nix 1.12 or higher export NIX_REMOTE=local?root=$PWD - ${nixUnstable}/bin/nix-store --load-db < ${nixRegistration contents} + ${nixUnstable}/bin/nix-store --load-db < ${nixRegistration contents}/db.dump + + # We fill the store in order to run the 'verify' command that + # generates hash and size of output paths. + # Note when Nix 1.12 is be the stable one, the database dump + # generated by the exportReferencesGraph function will + # contains sha and size. See + # https://github.com/NixOS/nix/commit/c2b0d8749f7e77afc1c4b3e8dd36b7ee9720af4a + storePaths=$(cat ${nixRegistration contents}/storePaths) + echo "Copying everything to /nix/store (will take a while)..." + cp -prd $storePaths nix/store/ + ${nixUnstable}/bin/nix-store --verify --check-contents + + mkdir -p nix/var/nix/gcroots/docker/ + for i in ${lib.concatStringsSep " " contents}; do + ln -s $i nix/var/nix/gcroots/docker/$(basename $i) + done; '' + extraCommands; }); }