Merge pull request #179801 from hercules-ci/fix-footgun-dockerTools-buildImage-contents

dockerTools.buildImage: Add copyToRoot to replace contents, explain usage

authored by Robert Hensing and committed by GitHub 613e7686 5cbfadba

+128 -40
+12 -3
doc/builders/images/dockertools.section.md
··· 20 20 fromImageName = null; 21 21 fromImageTag = "latest"; 22 22 23 - contents = pkgs.redis; 23 + copyToRoot = pkgs.buildEnv { 24 + name = "image-root"; 25 + paths = [ pkgs.redis ]; 26 + pathsToLink = [ "/bin" ]; 27 + }; 28 + 24 29 runAsRoot = '' 25 30 #!${pkgs.runtimeShell} 26 31 mkdir -p /data ··· 46 51 47 52 - `fromImageTag` can be used to further specify the tag of the base image within the repository, in case an image contains multiple tags. By default it's `null`, in which case `buildImage` will peek the first tag available for the base image. 48 53 49 - - `contents` is a derivation that will be copied in the new layer of the resulting image. This can be similarly seen as `ADD contents/ /` in a `Dockerfile`. By default it's `null`. 54 + - `copyToRoot` is a derivation that will be copied in the new layer of the resulting image. This can be similarly seen as `ADD contents/ /` in a `Dockerfile`. By default it's `null`. 50 55 51 56 - `runAsRoot` is a bash script that will run as root in an environment that overlays the existing layers of the base image with the new resulting layer, including the previously copied `contents` derivation. This can be similarly seen as `RUN ...` in a `Dockerfile`. 52 57 ··· 81 86 name = "hello"; 82 87 tag = "latest"; 83 88 created = "now"; 84 - contents = pkgs.hello; 89 + copyToRoot = pkgs.buildEnv { 90 + name = "image-root"; 91 + paths = [ pkgs.hello ]; 92 + pathsToLink = [ "/bin" ]; 93 + }; 85 94 86 95 config.Cmd = [ "/bin/hello" ]; 87 96 }
+9
nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
··· 305 305 </listitem> 306 306 <listitem> 307 307 <para> 308 + <literal>dockerTools.buildImage</literal> deprecates the 309 + misunderstood <literal>contents</literal> parameter, in favor 310 + of <literal>copyToRoot</literal>. Use 311 + <literal>copyToRoot = buildEnv { ... };</literal> or similar 312 + if you intend to add packages to <literal>/bin</literal>. 313 + </para> 314 + </listitem> 315 + <listitem> 316 + <para> 308 317 memtest86+ was updated from 5.00-coreboot-002 to 6.00-beta2. 309 318 It is now the upstream version from https://www.memtest.org/, 310 319 as coreboot’s fork is no longer available.
+3
nixos/doc/manual/release-notes/rl-2211.section.md
··· 114 114 115 115 - Matrix Synapse now requires entries in the `state_group_edges` table to be unique, in order to prevent accidentally introducing duplicate information (for example, because a database backup was restored multiple times). If your Synapse database already has duplicate rows in this table, this could fail with an error and require manual remediation. 116 116 117 + - `dockerTools.buildImage` deprecates the misunderstood `contents` parameter, in favor of `copyToRoot`. 118 + Use `copyToRoot = buildEnv { ... };` or similar if you intend to add packages to `/bin`. 119 + 117 120 - memtest86+ was updated from 5.00-coreboot-002 to 6.00-beta2. It is now the upstream version from https://www.memtest.org/, as coreboot's fork is no longer available. 118 121 119 122 - Add udev rules for the Teensy family of microcontrollers.
+5 -1
nixos/tests/docker-tools-cross.nix
··· 24 24 hello1 = remoteCrossPkgs.dockerTools.buildImage { 25 25 name = "hello1"; 26 26 tag = "latest"; 27 - contents = remoteCrossPkgs.hello; 27 + copyToRoot = remoteCrossPkgs.buildEnv { 28 + name = "image-root"; 29 + pathsToLink = [ "/bin" ]; 30 + paths = [ remoteCrossPkgs.hello ]; 31 + }; 28 32 }; 29 33 30 34 hello2 = remoteCrossPkgs.dockerTools.buildLayeredImage {
+27 -11
pkgs/build-support/docker/default.nix
··· 332 332 , # JSON containing configuration and metadata for this layer. 333 333 baseJson 334 334 , # Files to add to the layer. 335 - contents ? null 335 + copyToRoot ? null 336 336 , # When copying the contents into the image, preserve symlinks to 337 337 # directories (see `rsync -K`). Otherwise, transform those symlinks 338 338 # into directories. ··· 344 344 }: 345 345 runCommand "docker-layer-${name}" 346 346 { 347 - inherit baseJson contents extraCommands; 347 + inherit baseJson extraCommands; 348 + contents = copyToRoot; 348 349 nativeBuildInputs = [ jshon rsync tarsum ]; 349 350 } 350 351 '' ··· 390 391 , # Script to run as root. Bash. 391 392 runAsRoot 392 393 , # Files to add to the layer. If null, an empty layer will be created. 393 - contents ? null 394 + # To add packages to /bin, use `buildEnv` or similar. 395 + copyToRoot ? null 394 396 , # When copying the contents into the image, preserve symlinks to 395 397 # directories (see `rsync -K`). Otherwise, transform those symlinks 396 398 # into directories. ··· 418 420 419 421 inherit fromImage fromImageName fromImageTag diskSize; 420 422 421 - preMount = lib.optionalString (contents != null && contents != [ ]) '' 423 + preMount = lib.optionalString (copyToRoot != null && copyToRoot != [ ]) '' 422 424 echo "Adding contents..." 423 - for item in ${escapeShellArgs (map (c: "${c}") (toList contents))}; do 425 + for item in ${escapeShellArgs (map (c: "${c}") (toList copyToRoot))}; do 424 426 echo "Adding $item..." 425 427 rsync -a${if keepContentsDirlinks then "K" else "k"} --chown=0:0 $item/ layer/ 426 428 done ··· 500 502 , # Tag of the parent image; will be read from the image otherwise. 501 503 fromImageTag ? null 502 504 , # Files to put on the image (a nix store path or list of paths). 503 - contents ? null 505 + copyToRoot ? null 504 506 , # When copying the contents into the image, preserve symlinks to 505 507 # directories (see `rsync -K`). Otherwise, transform those symlinks 506 508 # into directories. ··· 517 519 diskSize ? 1024 518 520 , # Time of creation of the image. 519 521 created ? "1970-01-01T00:00:01Z" 522 + , # Deprecated. 523 + contents ? null 520 524 , 521 525 }: 522 526 523 527 let 528 + checked = 529 + lib.warnIf (contents != null) 530 + "in docker image ${name}: The contents parameter is deprecated. Change to copyToRoot if the contents are designed to be copied to the root filesystem, such as when you use `buildEnv` or similar between contents and your packages. Use copyToRoot = buildEnv { ... }; or similar if you intend to add packages to /bin." 531 + lib.throwIf (contents != null && copyToRoot != null) "in docker image ${name}: You can not specify both contents and copyToRoot." 532 + ; 533 + 534 + rootContents = if copyToRoot == null then contents else copyToRoot; 535 + 524 536 baseName = baseNameOf name; 525 537 526 538 # Create a JSON blob of the configuration. Set the date to unix zero. ··· 545 557 mkPureLayer 546 558 { 547 559 name = baseName; 548 - inherit baseJson contents keepContentsDirlinks extraCommands uid gid; 560 + inherit baseJson keepContentsDirlinks extraCommands uid gid; 561 + copyToRoot = rootContents; 549 562 } else 550 563 mkRootLayer { 551 564 name = baseName; 552 565 inherit baseJson fromImage fromImageName fromImageTag 553 - contents keepContentsDirlinks runAsRoot diskSize 566 + keepContentsDirlinks runAsRoot diskSize 554 567 extraCommands; 568 + copyToRoot = rootContents; 555 569 }; 556 570 result = runCommand "docker-image-${baseName}.tar.gz" 557 571 { ··· 715 729 ''; 716 730 717 731 in 718 - result; 732 + checked result; 719 733 720 734 # Merge the tarballs of images built with buildImage into a single 721 735 # tarball that contains all images. Running `docker load` on the resulting ··· 776 790 # contents. The main purpose is to be able to use nix commands in 777 791 # the container. 778 792 # Be careful since this doesn't work well with multilayer. 779 - buildImageWithNixDb = args@{ contents ? null, extraCommands ? "", ... }: ( 793 + # TODO: add the dependencies of the config json. 794 + buildImageWithNixDb = args@{ copyToRoot ? contents, contents ? null, extraCommands ? "", ... }: ( 780 795 buildImage (args // { 781 - extraCommands = (mkDbExtraCommand contents) + extraCommands; 796 + extraCommands = (mkDbExtraCommand copyToRoot) + extraCommands; 782 797 }) 783 798 ); 784 799 800 + # TODO: add the dependencies of the config json. 785 801 buildLayeredImageWithNixDb = args@{ contents ? null, extraCommands ? "", ... }: ( 786 802 buildLayeredImage (args // { 787 803 extraCommands = (mkDbExtraCommand contents) + extraCommands;
+72 -25
pkgs/build-support/docker/examples.nix
··· 24 24 bash = buildImage { 25 25 name = "bash"; 26 26 tag = "latest"; 27 - contents = pkgs.bashInteractive; 27 + copyToRoot = pkgs.buildEnv { 28 + name = "image-root"; 29 + paths = [ pkgs.bashInteractive ]; 30 + pathsToLink = [ "/bin" ]; 31 + }; 28 32 }; 29 33 30 34 # 2. service example, layered on another image ··· 36 40 fromImage = bash; 37 41 # fromImage = debian; 38 42 39 - contents = pkgs.redis; 43 + copyToRoot = pkgs.buildEnv { 44 + name = "image-root"; 45 + paths = [ pkgs.redis ]; 46 + pathsToLink = [ "/bin" ]; 47 + }; 48 + 40 49 runAsRoot = '' 41 50 mkdir -p /data 42 51 ''; ··· 118 127 # 5. example of multiple contents, emacs and vi happily coexisting 119 128 editors = buildImage { 120 129 name = "editors"; 121 - contents = [ 122 - pkgs.coreutils 123 - pkgs.bash 124 - pkgs.emacs 125 - pkgs.vim 126 - pkgs.nano 127 - ]; 130 + copyToRoot = pkgs.buildEnv { 131 + name = "image-root"; 132 + pathsToLink = [ "/bin" ]; 133 + paths = [ 134 + pkgs.coreutils 135 + pkgs.bash 136 + pkgs.emacs 137 + pkgs.vim 138 + pkgs.nano 139 + ]; 140 + }; 128 141 }; 129 142 130 143 # 6. nix example to play with the container nix store ··· 132 145 nix = buildImageWithNixDb { 133 146 name = "nix"; 134 147 tag = "latest"; 135 - contents = [ 136 - # nix-store uses cat program to display results as specified by 137 - # the image env variable NIX_PAGER. 138 - pkgs.coreutils 139 - pkgs.nix 140 - pkgs.bash 141 - ]; 148 + copyToRoot = pkgs.buildEnv { 149 + name = "image-root"; 150 + pathsToLink = [ "/bin" ]; 151 + paths = [ 152 + # nix-store uses cat program to display results as specified by 153 + # the image env variable NIX_PAGER. 154 + pkgs.coreutils 155 + pkgs.nix 156 + pkgs.bash 157 + ]; 158 + }; 142 159 config = { 143 160 Env = [ 144 161 "NIX_PAGER=cat" ··· 155 172 name = "onTopOfPulledImage"; 156 173 tag = "latest"; 157 174 fromImage = nixFromDockerHub; 158 - contents = [ pkgs.hello ]; 175 + copyToRoot = pkgs.buildEnv { 176 + name = "image-root"; 177 + pathsToLink = [ "/bin" ]; 178 + paths = [ pkgs.hello ]; 179 + }; 159 180 }; 160 181 161 182 # 8. regression test for erroneous use of eval and string expansion. ··· 163 184 runAsRootExtraCommands = pkgs.dockerTools.buildImage { 164 185 name = "runAsRootExtraCommands"; 165 186 tag = "latest"; 166 - contents = [ pkgs.coreutils ]; 187 + copyToRoot = pkgs.buildEnv { 188 + name = "image-root"; 189 + pathsToLink = [ "/bin" ]; 190 + paths = [ pkgs.coreutils ]; 191 + }; 167 192 # The parens here are to create problematic bash to embed and eval. In case 168 193 # this is *embedded* into the script (with nix expansion) the initial quotes 169 194 # will close the string and the following parens are unexpected ··· 176 201 unstableDate = pkgs.dockerTools.buildImage { 177 202 name = "unstable-date"; 178 203 tag = "latest"; 179 - contents = [ pkgs.coreutils ]; 204 + copyToRoot = pkgs.buildEnv { 205 + name = "image-root"; 206 + pathsToLink = [ "/bin" ]; 207 + paths = [ pkgs.coreutils ]; 208 + }; 180 209 created = "now"; 181 210 }; 182 211 ··· 265 294 name = "l3"; 266 295 fromImage = l2; 267 296 tag = "latest"; 268 - contents = [ pkgs.coreutils ]; 297 + copyToRoot = pkgs.buildEnv { 298 + name = "image-root"; 299 + pathsToLink = [ "/bin" ]; 300 + paths = [ pkgs.coreutils ]; 301 + }; 269 302 extraCommands = '' 270 303 mkdir -p tmp 271 304 echo layer3 > tmp/layer3 ··· 290 323 name = "child"; 291 324 fromImage = environmentVariablesParent; 292 325 tag = "latest"; 293 - contents = [ pkgs.coreutils ]; 326 + copyToRoot = pkgs.buildEnv { 327 + name = "image-root"; 328 + pathsToLink = [ "/bin" ]; 329 + paths = [ pkgs.coreutils ]; 330 + }; 294 331 config = { 295 332 Env = [ 296 333 "FROM_CHILD=true" ··· 424 461 name = "layers-unpack-order-${layerName}"; 425 462 tag = "latest"; 426 463 fromImage = parent; 427 - contents = [ pkgs.coreutils ]; 464 + copyToRoot = pkgs.buildEnv { 465 + name = "image-root"; 466 + pathsToLink = [ "/bin" ]; 467 + paths = [ pkgs.coreutils ]; 468 + }; 428 469 runAsRoot = '' 429 470 #!${pkgs.runtimeShell} 430 471 echo -n "${layerName}" >> /layer-order ··· 441 482 # buildImage without explicit tag 442 483 bashNoTag = pkgs.dockerTools.buildImage { 443 484 name = "bash-no-tag"; 444 - contents = pkgs.bashInteractive; 485 + # Not recommended. Use `buildEnv` between copy and packages to avoid file duplication. 486 + copyToRoot = pkgs.bashInteractive; 445 487 }; 446 488 447 489 # buildLayeredImage without explicit tag ··· 501 543 in crossPkgs.dockerTools.buildImage { 502 544 name = "hello-cross"; 503 545 tag = "latest"; 504 - contents = crossPkgs.hello; 546 + copyToRoot = pkgs.buildEnv { 547 + name = "image-root"; 548 + pathsToLink = [ "/bin" ]; 549 + paths = [ crossPkgs.hello ]; 550 + }; 505 551 }; 506 552 507 553 # layered image where a store path is itself a symlink ··· 643 689 build-image-with-path = buildImage { 644 690 name = "build-image-with-path"; 645 691 tag = "latest"; 646 - contents = [ pkgs.bashInteractive ./test-dummy ]; 692 + # Not recommended. Use `buildEnv` between copy and packages to avoid file duplication. 693 + copyToRoot = [ pkgs.bashInteractive ./test-dummy ]; 647 694 }; 648 695 649 696 layered-image-with-path = pkgs.dockerTools.streamLayeredImage {