diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix index 51b472fcf9ce..2375d15b3813 100644 --- a/nixos/tests/docker-tools.nix +++ b/nixos/tests/docker-tools.nix @@ -124,6 +124,16 @@ import ./make-test-python.nix ({ pkgs, ... }: { f"docker run --rm ${examples.layersOrder.imageName} cat /tmp/layer{index}" ) + with subtest("Ensure environment variables are correctly inherited"): + docker.succeed( + "docker load --input='${examples.environmentVariables}'" + ) + out = docker.succeed("docker run --rm ${examples.environmentVariables.imageName} env") + env = out.splitlines() + assert "FROM_PARENT=true" in env, "envvars from the parent should be preserved" + assert "FROM_CHILD=true" in env, "envvars from the child should be preserved" + assert "LAST_LAYER=child" in env, "envvars from the child should take priority" + with subtest("Ensure image with only 2 layers can be loaded"): docker.succeed( "docker load --input='${examples.two-layered-image}'" diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index bee6e37cccbb..f2a1378b8b27 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -773,13 +773,17 @@ rec { mkdir image touch baseFiles + baseEnvs='[]' if [[ -n "$fromImage" ]]; then echo "Unpacking base image..." tar -C image -xpf "$fromImage" + # Store the layers and the environment variables from the base image cat ./image/manifest.json | jq -r '.[0].Layers | .[]' > layer-list + configName="$(cat ./image/manifest.json | jq -r '.[0].Config')" + baseEnvs="$(cat "./image/$configName" | jq '.config.Env // []')" - # Do not import the base image configuration and manifest + # Otherwise do not import the base image configuration and manifest chmod a+w image image/*.json rm -f image/*.json @@ -859,7 +863,8 @@ rec { ) | sponge layer-list # Create image json and image manifest - imageJson=$(cat ${baseJson} | jq ". + {\"rootfs\": {\"diff_ids\": [], \"type\": \"layers\"}}") + imageJson=$(cat ${baseJson} | jq '.config.Env = $baseenv + .config.Env' --argjson baseenv "$baseEnvs") + imageJson=$(echo "$imageJson" | jq ". + {\"rootfs\": {\"diff_ids\": [], \"type\": \"layers\"}}") manifestJson=$(jq -n "[{\"RepoTags\":[\"$imageName:$imageTag\"]}]") for layerTar in $(cat ./layer-list); do diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix index f42b35e64943..c6cf595da103 100644 --- a/pkgs/build-support/docker/examples.nix +++ b/pkgs/build-support/docker/examples.nix @@ -231,14 +231,41 @@ rec { ''; }; - # 14. Create another layered image, for comparing layers with image 10. + # 14. Environment variable inheritance. + # Child image should inherit parents environment variables, + # optionally overriding them. + environmentVariables = let + parent = pkgs.dockerTools.buildImage { + name = "parent"; + tag = "latest"; + config = { + Env = [ + "FROM_PARENT=true" + "LAST_LAYER=parent" + ]; + }; + }; + in pkgs.dockerTools.buildImage { + name = "child"; + fromImage = parent; + tag = "latest"; + contents = [ pkgs.coreutils ]; + config = { + Env = [ + "FROM_CHILD=true" + "LAST_LAYER=child" + ]; + }; + }; + + # 15. Create another layered image, for comparing layers with image 10. another-layered-image = pkgs.dockerTools.buildLayeredImage { name = "another-layered-image"; tag = "latest"; config.Cmd = [ "${pkgs.hello}/bin/hello" ]; }; - # 15. Create a layered image with only 2 layers + # 16. Create a layered image with only 2 layers two-layered-image = pkgs.dockerTools.buildLayeredImage { name = "two-layered-image"; tag = "latest"; @@ -247,7 +274,7 @@ rec { maxLayers = 2; }; - # 16. Create a layered image with more packages than max layers. + # 17. Create a layered image with more packages than max layers. # coreutils and hello are part of the same layer bulk-layer = pkgs.dockerTools.buildLayeredImage { name = "bulk-layer"; @@ -258,7 +285,7 @@ rec { maxLayers = 2; }; - # 17. Create a "layered" image without nix store layers. This is not + # 18. Create a "layered" image without nix store layers. This is not # recommended, but can be useful for base images in rare cases. no-store-paths = pkgs.dockerTools.buildLayeredImage { name = "no-store-paths";