nlewo / nix2container

An archive-less dockerTools.buildImage implementation
Apache License 2.0
501 stars 45 forks source link

nixDatabase contains paths which are not part of the image #94

Closed kolloch closed 9 months ago

kolloch commented 10 months ago

In nixDatabase = makeNixDatabase ([configFile] ++ copyToRootList ++ layers); store paths are added to the nixDatabase which are actually not in the image itself -- i.e. the image configurations.

That leads to errors when the resulting image is used to build itself again. The database will claim that the config is already in the store but then it cannot be opened.

nlewo commented 10 months ago

This is because the configuration file path is explicitly ignored to avoid building a new layer when a configuration parameter is updated. We need to take the configuration file into account in order to create a layer with its closure but we don't need to put the configuration into a layer since this configuration file already part of the OCI image itself.

So, I htink we would have two options:

kolloch commented 10 months ago

Even though the config files are tiny, I also like the first approach more.

So I guess it is about filtering the storepaths specified in the ignore setting of the layers? Is an "ignored" path only ignored in the same layer or globally? => checked: per layer

I think only in the same layer would work as expected but would also be so much more complicated: Then we would need to calculate the closure of each layer and subtract the ignore path(s) and then create the union.

nlewo commented 10 months ago

The nix2container binary has an option to explicitly ignore a path when building the tar of the layer. We then provide the path of the config file. So, we don't have to fix anything regarding the layers construction.

However, the configuration file path is not ignored when the Nix database is built. To build this database, we use the pkgs.closureInfo function which generates a file containing all store paths of the closure. I don't remember how this file looks like, but to fix this issue, we would have to modify this file by excluding the path of the configuration file. Since the configuration file is not a dependency of another store path, we could exclude it without breaking the closure graph.

So, in pseudo code, i think it would look like:

-  makeNixDatabase = paths: pkgs.runCommand "nix-database" {} ''
+  makeNixDatabase = configurationFilePath: paths: pkgs.runCommand "nix-database" {} ''
     mkdir $out
     echo "Generating the nix database..."
     export NIX_REMOTE=local?root=$out
     # A user is required by nix
     # https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
     export USER=nobody
-    ${pkgs.nix}/bin/nix-store --load-db < ${pkgs.closureInfo {rootPaths = paths;}}/registration
+    registration=${pkgs.closureInfo {rootPaths = paths;}}/registration
+    filtered_registration=$(something-to-remove-path-in-the-registration-file ${configurationFilePath} registration)
+    ${pkgs.nix}/bin/nix-store --load-db < filtered_registration

     mkdir -p $out/nix/var/nix/gcroots/docker/
     for i in ${l.concatStringsSep " " paths}; do

(i don't have time atm to dig more :()