From ebb911cc0b31dd39dfaf61f206967e47e92547cb Mon Sep 17 00:00:00 2001 From: Brian McKenna <bmckenna@atlassian.com> Date: Thu, 10 Mar 2016 18:29:28 +1100 Subject: [PATCH 1/2] dockerTools: remove tarballs functionality I think the intention of this functionality was to provide a simple alternative to the "runAsRoot" and "contents" attributes. The implementation caused very slow builds of Docker images. Almost all of the build time was spent in IO for tar, due to tarballs being created, immediately extracted, then recreated. I had 30 minute builds on some of my images which are now down to less than 2 minutes. A couple of other users on #nix IRC have observed similar improvements. The implementation also mutated the produced Docker layers without changing their hashes. Using non-empty tarballs would produce images which got cached incorrectly in Docker. I have a commit which just fixes the performance problem but I opted to completely remove the tarball feature after I found out that it didn't correctly implement the Docker Image Specification due to the broken hashing. --- pkgs/build-support/docker/default.nix | 70 ++++++--------------------- 1 file changed, 15 insertions(+), 55 deletions(-) diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index 8e4a51071e33..4c4999a42b4b 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -45,27 +45,6 @@ rec { done ''; - mkTarball = { name ? "docker-tar", drv, onlyDeps ? false }: - runCommand "${name}.tar.gz" rec { - inherit drv onlyDeps; - - drvClosure = writeReferencesToFile drv; - - } '' - while read dep; do - echo Copying $dep - dir="$(dirname "$dep")" - mkdir -p "rootfs/$dir" - cp -drf --preserve=mode $dep "rootfs/$dir/" - done < "$drvClosure" - - if [ -z "$onlyDeps" ]; then - cp -drf --preserve=mode $drv/* rootfs/ - fi - - tar -C rootfs/ -cpzf $out . - ''; - shellScript = text: writeScript "script.sh" '' #!${stdenv.shell} @@ -99,16 +78,6 @@ EOF fi ''; - # Append to tar instead of unpacking - mergeTarballs = tarballs: - runCommand "merge-tars" { inherit tarballs; } '' - mkdir tmp - for tb in $tarballs; do - tar -C tmp -xkpf $tb - done - tar -C tmp -cpzf $out . - ''; - runWithOverlay = { name , fromImage ? null, fromImageName ? null, fromImageTag ? null , diskSize ? 1024, preMount ? "", postMount ? "", postUmount ? "" }: vmTools.runInLinuxVM ( @@ -182,7 +151,7 @@ EOF postMount = '' echo Packing raw image - tar -C mnt -czf $out . + tar -C mnt -cf $out . ''; }; @@ -262,8 +231,8 @@ EOF # 6. repack the image buildImage = args@{ name, tag ? "latest" , fromImage ? null, fromImageName ? null, fromImageTag ? null - , contents ? null, tarballs ? [], config ? null - , runAsRoot ? null, diskSize ? 1024, extraCommands ? "" }: + , contents ? null, config ? null, runAsRoot ? null + , diskSize ? 1024, extraCommands ? "" }: let @@ -275,14 +244,10 @@ EOF os = "linux"; config = config; }); - + layer = (if runAsRoot == null then mkPureLayer { inherit baseJson contents extraCommands; } else mkRootLayer { inherit baseJson fromImage fromImageName fromImageTag contents runAsRoot diskSize extraCommands; }); - depsTarball = mkTarball { name = "${baseName}-deps"; - drv = layer; - onlyDeps = true; }; - result = runCommand "${baseName}.tar.gz" { buildInputs = [ jshon ]; @@ -290,7 +255,7 @@ EOF imageTag = tag; inherit fromImage baseJson; - mergedTarball = if tarballs == [] then depsTarball else mergeTarballs ([ depsTarball ] ++ tarballs); + layerClosure = writeReferencesToFile layer; passthru = { buildArgs = args; @@ -320,22 +285,17 @@ EOF mkdir temp cp ${layer}/* temp/ chmod ug+w temp/* - - echo Adding dependencies + + touch layerFiles + for dep in $(cat $layerClosure); do + find $dep >> layerFiles + done + + echo Adding layer tar -tf temp/layer.tar >> baseFiles - tar -tf "$mergedTarball" | grep -v ${layer} > layerFiles - if [ "$(wc -l layerFiles|cut -d ' ' -f 1)" -gt 3 ]; then - sed -i -e 's|^[\./]\+||' baseFiles layerFiles - comm <(sort -n baseFiles|uniq) <(sort -n layerFiles|uniq) -1 -3 > newFiles - mkdir deps - pushd deps - tar -xpf "$mergedTarball" --no-recursion --files-from ../newFiles 2>/dev/null || true - tar -rf ../temp/layer.tar --no-recursion --files-from ../newFiles 2>/dev/null || true - popd - else - echo No new deps, no diffing needed - fi - + comm <(sort -n baseFiles|uniq) <(sort -n layerFiles|uniq|grep -v ${layer}) -1 -3 > newFiles + tar -rpf temp/layer.tar --no-recursion --files-from newFiles 2>/dev/null || true + echo Adding meta if [ -n "$parentID" ]; then From d150fe89154e176dcf8b71ad64a771213aee0c1e Mon Sep 17 00:00:00 2001 From: Brian McKenna <bmckenna@atlassian.com> Date: Mon, 11 Apr 2016 16:31:15 +1000 Subject: [PATCH 2/2] dockerTools: use pigz for final image tar Saves a few seconds on large images. --- pkgs/build-support/docker/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index 4c4999a42b4b..1f14bda203db 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -1,5 +1,5 @@ { stdenv, lib, callPackage, runCommand, writeReferencesToFile, writeText, vmTools, writeScript -, docker, shadow, utillinux, coreutils, jshon, e2fsprogs, goPackages }: +, docker, shadow, utillinux, coreutils, jshon, e2fsprogs, goPackages, pigz }: # WARNING: this API is unstable and may be subject to backwards-incompatible changes in the future. @@ -249,7 +249,7 @@ EOF then mkPureLayer { inherit baseJson contents extraCommands; } else mkRootLayer { inherit baseJson fromImage fromImageName fromImageTag contents runAsRoot diskSize extraCommands; }); result = runCommand "${baseName}.tar.gz" { - buildInputs = [ jshon ]; + buildInputs = [ jshon pigz ]; imageName = name; imageTag = tag; @@ -317,7 +317,7 @@ EOF chmod -R a-w image echo Cooking the image - tar -C image -czf $out . + tar -C image -c . | pigz > $out ''; in