From b3f68289df646a82c9b87d866244510ff1d2866a Mon Sep 17 00:00:00 2001 From: Louis Blin <45168934+lbpdt@users.noreply.github.com> Date: Thu, 25 Mar 2021 16:38:37 +0000 Subject: [PATCH] dockerTools.streamLayeredImage: resolve duplicate env vars For images running on Kubernetes, there is no guarantee on how duplicate environment variables in the image config will be handled. This seems to be different from Docker, where the last environment variable value is consistently selected. The current code for `streamLayeredImage` was exploiting that assumption to easily propagate environment variables from the base image, leaving duplicates unchecked. It should rather resolve these duplicates to ensure consistent behavior on Docker and Kubernetes. --- nixos/tests/docker-tools.nix | 15 +++++++++++++++ pkgs/build-support/docker/stream_layered_image.py | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix index dd287883c98..a0e81b613ce 100644 --- a/nixos/tests/docker-tools.nix +++ b/nixos/tests/docker-tools.nix @@ -221,6 +221,21 @@ import ./make-test-python.nix ({ pkgs, ... }: { 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 inherited environment variables of layered images are correctly resolved" + ): + # Read environment variables as stored in image config + config = docker.succeed( + "tar -xOf ${examples.environmentVariablesLayered} manifest.json | ${pkgs.jq}/bin/jq -r .[].Config" + ).strip() + out = docker.succeed( + f"tar -xOf ${examples.environmentVariablesLayered} {config} | ${pkgs.jq}/bin/jq -r '.config.Env | .[]'" + ) + env = out.splitlines() + assert ( + sum(entry.startswith("LAST_LAYER") for entry in env) == 1 + ), "envvars overridden by child should be unique" + 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/stream_layered_image.py b/pkgs/build-support/docker/stream_layered_image.py index 3e5781ba1c8..d7c63eb43a7 100644 --- a/pkgs/build-support/docker/stream_layered_image.py +++ b/pkgs/build-support/docker/stream_layered_image.py @@ -202,7 +202,9 @@ def overlay_base_config(from_image, final_config): # Preserve environment from base image final_env = base_config.get("Env", []) + final_config.get("Env", []) if final_env: - final_config["Env"] = final_env + # Resolve duplicates (last one wins) and format back as list + resolved_env = {entry.split("=", 1)[0]: entry for entry in final_env} + final_config["Env"] = list(resolved_env.values()) return final_config