From 7039cae78a98609775eaf28c0b3f7fcbe8c2ea39 Mon Sep 17 00:00:00 2001 From: Rok Garbas Date: Sun, 31 Oct 2021 00:22:35 +0200 Subject: [PATCH 1/3] Docker image with Nix inside --- docker.nix | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 7 ++ 2 files changed, 271 insertions(+) create mode 100644 docker.nix diff --git a/docker.nix b/docker.nix new file mode 100644 index 000000000..40af2f38b --- /dev/null +++ b/docker.nix @@ -0,0 +1,264 @@ +{ pkgs ? import { } +, lib ? pkgs.lib +, name ? "nix" +, tag ? "latest" +, crossSystem ? null +, channelName ? "nixpkgs" +, channelURL ? "https://nixos.org/channels/nixpkgs-unstable" +}: +let + buildPkgs = pkgs; + targetPkgs = + if crossSystem != null && crossSystem != pkgs.system + then { + aarch64-linux = pkgs.pkgsCross.aarch64-multiplatform; + armv7l-linux = pkgs.pkgsCross.armv7l-hf-multiplatform.system; + x86_64-linux = pkgs.pkgsCross.gnu64; + powerpc64le-linux = pkgs.pkgsCross.musl-power; + i686-linux = pkgs.pkgsCross.gnu32; + }.${crossSystem} + else pkgs; + + defaultPkgs = [ + targetPkgs.nix + targetPkgs.bashInteractive + targetPkgs.coreutils-full + targetPkgs.gnutar + targetPkgs.gzip + targetPkgs.gnugrep + targetPkgs.which + targetPkgs.curl + targetPkgs.less + targetPkgs.wget + targetPkgs.man + targetPkgs.cacert.out + targetPkgs.findutils + ]; + + users = { + + root = { + uid = 0; + shell = "/bin/bash"; + home = "/root"; + gid = 0; + }; + + } // lib.listToAttrs ( + map + ( + n: { + name = "nixbld${toString n}"; + value = { + uid = 30000 + n; + gid = 30000; + groups = [ "nixbld" ]; + description = "Nix build user ${toString n}"; + }; + } + ) + (lib.lists.range 1 32) + ); + + groups = { + root.gid = 0; + nixbld.gid = 30000; + }; + + userToPasswd = ( + k: + { uid + , gid ? 65534 + , home ? "/var/empty" + , description ? "" + , shell ? "/bin/false" + , groups ? [ ] + }: "${k}:x:${toString uid}:${toString gid}:${description}:${home}:${shell}" + ); + passwdContents = ( + lib.concatStringsSep "\n" + (lib.attrValues (lib.mapAttrs userToPasswd users)) + ); + + userToShadow = k: { ... }: "${k}:!:1::::::"; + shadowContents = ( + lib.concatStringsSep "\n" + (lib.attrValues (lib.mapAttrs userToShadow users)) + ); + + # Map groups to members + # { + # group = [ "user1" "user2" ]; + # } + groupMemberMap = ( + let + # Create a flat list of user/group mappings + mappings = ( + builtins.foldl' + ( + acc: user: + let + groups = users.${user}.groups or [ ]; + in + acc ++ map + (group: { + inherit user group; + }) + groups + ) + [ ] + (lib.attrNames users) + ); + in + ( + builtins.foldl' + ( + acc: v: acc // { + ${v.group} = acc.${v.group} or [ ] ++ [ v.user ]; + } + ) + { } + mappings) + ); + + groupToGroup = k: { gid }: + let + members = groupMemberMap.${k} or [ ]; + in + "${k}:x:${toString gid}:${lib.concatStringsSep "," members}"; + groupContents = ( + lib.concatStringsSep "\n" + (lib.attrValues (lib.mapAttrs groupToGroup groups)) + ); + + nixConf = { + sandbox = "false"; + build-users-group = "nixbld"; + trusted-public-keys = "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="; + }; + nixConfContents = (lib.concatStringsSep "\n" (lib.mapAttrsFlatten (n: v: "${n} = ${v}") nixConf)) + "\n"; + + baseSystem = + let + nixpkgs = targetPkgs.path; + channel = targetPkgs.runCommand "channel-nixos" { } '' + mkdir $out + ln -s ${nixpkgs} $out/nixpkgs + echo "[]" > $out/manifest.nix + ''; + rootEnv = pkgs.buildEnv { + name = "root-profile-env"; + paths = defaultPkgs; + }; + profile = targetPkgs.runCommand "user-environment" { } '' + mkdir $out + cp -a ${rootEnv}/* $out/ + + cat > $out/manifest.nix < $out/etc/passwd + echo "" >> $out/etc/passwd + + cat $groupContentsPath > $out/etc/group + echo "" >> $out/etc/group + + cat $shadowContentsPath > $out/etc/shadow + echo "" >> $out/etc/shadow + + mkdir -p $out/usr + ln -s /nix/var/nix/profiles/share $out/usr/ + + mkdir -p $out/nix/var/nix/gcroots + + mkdir $out/tmp + + mkdir -p $out/etc/nix + cat $nixConfContentsPath > $out/etc/nix/nix.conf + + mkdir -p $out/root + mkdir -p $out/nix/var/nix/profiles/per-user/root + + ln -s ${profile} $out/nix/var/nix/profiles/default-1-link + ln -s $out/nix/var/nix/profiles/default-1-link $out/nix/var/nix/profiles/default + ln -s /nix/var/nix/profiles/default $out/root/.nix-profile + + ln -s ${channel} $out/nix/var/nix/profiles/per-user/root/channels-1-link + ln -s $out/nix/var/nix/profiles/per-user/root/channels-1-link $out/nix/var/nix/profiles/per-user/root/channels + + mkdir -p $out/root/.nix-defexpr + ln -s $out/nix/var/nix/profiles/per-user/root/channels $out/root/.nix-defexpr/channels + echo "${channelURL} ${channelName}" > $out/root/.nix-channels + + mkdir -p $out/bin $out/usr/bin + ln -s ${targetPkgs.coreutils}/bin/env $out/usr/bin/env + ln -s ${targetPkgs.bashInteractive}/bin/bash $out/bin/sh + ''; + +in +targetPkgs.dockerTools.buildLayeredImageWithNixDb { + + inherit name tag; + + contents = [ baseSystem ]; + + extraCommands = '' + rm -rf nix-support + ln -s /nix/var/nix/profiles nix/var/nix/gcroots/profiles + ''; + + config = { + Cmd = [ "/root/.nix-profile/bin/bash" ]; + Env = [ + "USER=root" + "PATH=${lib.concatStringsSep ":" [ + "/root/.nix-profile/bin" + "/nix/var/nix/profiles/default/bin" + "/nix/var/nix/profiles/default/sbin" + ]}" + "MANPATH=${lib.concatStringsSep ":" [ + "/root/.nix-profile/share/man" + "/nix/var/nix/profiles/default/share/man" + ]}" + "SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" + "GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" + "NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" + "NIX_PATH=/nix/var/nix/profiles/per-user/root/channels:/root/.nix-defexpr/channels" + ]; + }; + +} diff --git a/flake.nix b/flake.nix index a834448ce..c5781ff6d 100644 --- a/flake.nix +++ b/flake.nix @@ -404,6 +404,13 @@ installerScript = installScriptFor [ "x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" "armv6l-linux" "armv7l-linux" ]; installerScriptForGHA = installScriptFor [ "x86_64-linux" "x86_64-darwin" "armv6l-linux" "armv7l-linux"]; + # docker image with Nix inside + dockerImage = nixpkgs.lib.genAttrs linux64BitSystems (system: + import ./docker.nix { + pkgs = nixpkgsFor.${system}; + tag = version; + }); + # Line coverage analysis. coverage = with nixpkgsFor.x86_64-linux; From 06ce280a15801f255b89f2443eb689c037d13247 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 2 Nov 2021 14:03:55 +0100 Subject: [PATCH 2/3] docker.nix: Use 'with' Co-authored-by: Sandro --- docker.nix | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docker.nix b/docker.nix index 40af2f38b..316d57a36 100644 --- a/docker.nix +++ b/docker.nix @@ -19,20 +19,20 @@ let }.${crossSystem} else pkgs; - defaultPkgs = [ - targetPkgs.nix - targetPkgs.bashInteractive - targetPkgs.coreutils-full - targetPkgs.gnutar - targetPkgs.gzip - targetPkgs.gnugrep - targetPkgs.which - targetPkgs.curl - targetPkgs.less - targetPkgs.wget - targetPkgs.man - targetPkgs.cacert.out - targetPkgs.findutils + defaultPkgs = with targetPkgs; [ + nix + bashInteractive + coreutils-full + gnutar + gzip + gnugrep + which + curl + less + wget + man + cacert.out + findutils ]; users = { From 066f990d0aedc8266ab1c2a4510bc2fa62ead3bc Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 16 Nov 2021 10:32:26 -0500 Subject: [PATCH 3/3] Make docker.nix match Nixpkgs's idioms 1. `target` is the wrong name, that is just for compilers per out standard terminology. We just need to worry about "build" and "host". 2. We only need one `pkgs`. `pkgs.buildPackages` is how we get anything we need at build time. 3. `crossSystem` is the name of a nixpkgs parameter that is actually an attribute set, not a 2-part "cpu-os" string. 3. `pkgsCross` effectively evaluates Nixpkgs twice, which is inefficient. It is just there for people poking around the CLI / REPL (and I am skeptical even that is a good idea), and *not* what written code should use, especially code that is merely parametric in the package set it is given. 4. We don't need to memoize Nixpkgs here because we are only doing one pkg set at a time (no `genAttrs`) so it's better to just delete all this stuff. `flake.nix` instead would do something like that, with `genAttrs` (though without `pkgsCross`), if and when we have hydra jobs for cross builds. --- docker.nix | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/docker.nix b/docker.nix index 316d57a36..2a13c23fb 100644 --- a/docker.nix +++ b/docker.nix @@ -2,24 +2,11 @@ , lib ? pkgs.lib , name ? "nix" , tag ? "latest" -, crossSystem ? null , channelName ? "nixpkgs" , channelURL ? "https://nixos.org/channels/nixpkgs-unstable" }: let - buildPkgs = pkgs; - targetPkgs = - if crossSystem != null && crossSystem != pkgs.system - then { - aarch64-linux = pkgs.pkgsCross.aarch64-multiplatform; - armv7l-linux = pkgs.pkgsCross.armv7l-hf-multiplatform.system; - x86_64-linux = pkgs.pkgsCross.gnu64; - powerpc64le-linux = pkgs.pkgsCross.musl-power; - i686-linux = pkgs.pkgsCross.gnu32; - }.${crossSystem} - else pkgs; - - defaultPkgs = with targetPkgs; [ + defaultPkgs = with pkgs; [ nix bashInteractive coreutils-full @@ -140,17 +127,17 @@ let baseSystem = let - nixpkgs = targetPkgs.path; - channel = targetPkgs.runCommand "channel-nixos" { } '' + nixpkgs = pkgs.path; + channel = pkgs.runCommand "channel-nixos" { } '' mkdir $out ln -s ${nixpkgs} $out/nixpkgs echo "[]" > $out/manifest.nix ''; - rootEnv = pkgs.buildEnv { + rootEnv = pkgs.buildPackages.buildEnv { name = "root-profile-env"; paths = defaultPkgs; }; - profile = targetPkgs.runCommand "user-environment" { } '' + profile = pkgs.buildPackages.runCommand "user-environment" { } '' mkdir $out cp -a ${rootEnv}/* $out/ @@ -175,7 +162,7 @@ let EOF ''; in - targetPkgs.runCommand "base-system" + pkgs.runCommand "base-system" { inherit passwdContents groupContents shadowContents nixConfContents; passAsFile = [ @@ -225,12 +212,12 @@ let echo "${channelURL} ${channelName}" > $out/root/.nix-channels mkdir -p $out/bin $out/usr/bin - ln -s ${targetPkgs.coreutils}/bin/env $out/usr/bin/env - ln -s ${targetPkgs.bashInteractive}/bin/bash $out/bin/sh + ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env + ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh ''; in -targetPkgs.dockerTools.buildLayeredImageWithNixDb { +pkgs.dockerTools.buildLayeredImageWithNixDb { inherit name tag;