docker: format

This commit is contained in:
Sandro Jäckel 2021-08-10 10:24:15 +02:00
parent daa36171c0
commit ceb417aaf1
No known key found for this signature in database
GPG key ID: 3AF5A43A3EECC2E5

View file

@ -1,49 +1,47 @@
{
bashInteractive,
buildPackages,
cacert,
callPackage,
closureInfo,
coreutils,
e2fsprogs,
fakeroot,
findutils,
go,
jq,
jshon,
lib,
makeWrapper,
moreutils,
nix,
pigz,
pkgs,
rsync,
runCommand,
runtimeShell,
shadow,
skopeo,
storeDir ? builtins.storeDir,
substituteAll,
symlinkJoin,
util-linux,
vmTools,
writeReferencesToFile,
writeScript,
writeText,
writeTextDir,
writePython3,
system, # Note: This is the cross system we're compiling for
{ bashInteractive
, buildPackages
, cacert
, callPackage
, closureInfo
, coreutils
, e2fsprogs
, fakeroot
, findutils
, go
, jq
, jshon
, lib
, makeWrapper
, moreutils
, nix
, pigz
, pkgs
, rsync
, runCommand
, runtimeShell
, shadow
, skopeo
, storeDir ? builtins.storeDir
, substituteAll
, symlinkJoin
, util-linux
, vmTools
, writeReferencesToFile
, writeScript
, writeText
, writeTextDir
, writePython3
, system
, # Note: This is the cross system we're compiling for
}:
let
inherit (lib)
optionals
;
mkDbExtraCommand = contents: let
mkDbExtraCommand = contents:
let
contentsList = if builtins.isList contents then contents else [ contents ];
in ''
in
''
echo "Generating the nix database..."
echo "Warning: only the database of the deepest Nix layer is loaded."
echo " If you want to use nix commands in the container, it would"
@ -70,13 +68,13 @@ let
in
rec {
examples = callPackage ./examples.nix {
inherit buildImage buildLayeredImage fakeNss pullImage shadowSetup buildImageWithNixDb;
};
pullImage = let
fixName = name: builtins.replaceStrings ["/" ":"] ["-" "-"] name;
pullImage =
let
fixName = name: builtins.replaceStrings [ "/" ":" ] [ "-" "-" ] name;
in
{ imageName
# To find the digest of an image, you can use skopeo:
@ -96,7 +94,8 @@ rec {
, name ? fixName "docker-image-${finalImageName}-${finalImageTag}.tar"
}:
runCommand name {
runCommand name
{
inherit imageDigest;
imageName = finalImageName;
imageTag = finalImageTag;
@ -126,11 +125,12 @@ rec {
tarsum = pkgs.tarsum;
# buildEnv creates symlinks to dirs, which is hard to edit inside the overlay VM
mergeDrvs = {
derivations,
onlyDeps ? false
mergeDrvs =
{ derivations
, onlyDeps ? false
}:
runCommand "merge-drvs" {
runCommand "merge-drvs"
{
inherit derivations onlyDeps;
} ''
if [[ -n "$onlyDeps" ]]; then
@ -180,19 +180,20 @@ rec {
'';
# Run commands in a virtual machine.
runWithOverlay = {
name,
fromImage ? null,
fromImageName ? null,
fromImageTag ? null,
diskSize ? 1024,
preMount ? "",
postMount ? "",
postUmount ? ""
runWithOverlay =
{ name
, fromImage ? null
, fromImageName ? null
, fromImageTag ? null
, diskSize ? 1024
, preMount ? ""
, postMount ? ""
, postUmount ? ""
}:
let
result = vmTools.runInLinuxVM (
runCommand name {
runCommand name
{
preVM = vmTools.createEmptyImage {
size = diskSize;
fullName = "docker-run-disk";
@ -277,7 +278,7 @@ rec {
${postUmount}
'');
in
runCommand name {} ''
runCommand name { } ''
mkdir -p $out
cd ${result}
cp layer.tar json VERSION $out
@ -293,7 +294,6 @@ rec {
'';
};
# Create an executable shell script which has the coreutils in its
# PATH. Since root scripts are executed in a blank environment, even
# things like `ls` or `echo` will be missing.
@ -306,21 +306,25 @@ rec {
'';
# Create a "layer" (set of files).
mkPureLayer = {
mkPureLayer =
{
# Name of the layer
name,
# JSON containing configuration and metadata for this layer.
baseJson,
# Files to add to the layer.
contents ? null,
# When copying the contents into the image, preserve symlinks to
name
, # JSON containing configuration and metadata for this layer.
baseJson
, # Files to add to the layer.
contents ? null
, # When copying the contents into the image, preserve symlinks to
# directories (see `rsync -K`). Otherwise, transform those symlinks
# into directories.
keepContentsDirlinks ? false,
# Additional commands to run on the layer before it is tar'd up.
extraCommands ? "", uid ? 0, gid ? 0
keepContentsDirlinks ? false
, # Additional commands to run on the layer before it is tar'd up.
extraCommands ? ""
, uid ? 0
, gid ? 0
}:
runCommand "docker-layer-${name}" {
runCommand "docker-layer-${name}"
{
inherit baseJson contents extraCommands;
nativeBuildInputs = [ jshon rsync tarsum ];
}
@ -360,40 +364,42 @@ rec {
# Make a "root" layer; required if we need to execute commands as a
# privileged user on the image. The commands themselves will be
# performed in a virtual machine sandbox.
mkRootLayer = {
mkRootLayer =
{
# Name of the image.
name,
# Script to run as root. Bash.
runAsRoot,
# Files to add to the layer. If null, an empty layer will be created.
contents ? null,
# When copying the contents into the image, preserve symlinks to
name
, # Script to run as root. Bash.
runAsRoot
, # Files to add to the layer. If null, an empty layer will be created.
contents ? null
, # When copying the contents into the image, preserve symlinks to
# directories (see `rsync -K`). Otherwise, transform those symlinks
# into directories.
keepContentsDirlinks ? false,
# JSON containing configuration and metadata for this layer.
baseJson,
# Existing image onto which to append the new layer.
fromImage ? null,
# Name of the image we're appending onto.
fromImageName ? null,
# Tag of the image we're appending onto.
fromImageTag ? null,
# How much disk to allocate for the temporary virtual machine.
diskSize ? 1024,
# Commands (bash) to run on the layer; these do not require sudo.
keepContentsDirlinks ? false
, # JSON containing configuration and metadata for this layer.
baseJson
, # Existing image onto which to append the new layer.
fromImage ? null
, # Name of the image we're appending onto.
fromImageName ? null
, # Tag of the image we're appending onto.
fromImageTag ? null
, # How much disk to allocate for the temporary virtual machine.
diskSize ? 1024
, # Commands (bash) to run on the layer; these do not require sudo.
extraCommands ? ""
}:
# Generate an executable script from the `runAsRoot` text.
let
runAsRootScript = shellScript "run-as-root.sh" runAsRoot;
extraCommandsScript = shellScript "extra-commands.sh" extraCommands;
in runWithOverlay {
in
runWithOverlay {
name = "docker-layer-${name}";
inherit fromImage fromImageName fromImageTag diskSize;
preMount = lib.optionalString (contents != null && contents != []) ''
preMount = lib.optionalString (contents != null && contents != [ ]) ''
echo "Adding contents..."
for item in ${toString contents}; do
echo "Adding $item..."
@ -445,11 +451,12 @@ rec {
'';
};
buildLayeredImage = {name, ...}@args:
buildLayeredImage = { name, ... }@args:
let
stream = streamLayeredImage args;
in
runCommand "${baseNameOf name}.tar.gz" {
runCommand "${baseNameOf name}.tar.gz"
{
inherit (stream) imageName;
passthru = { inherit (stream) imageTag; };
nativeBuildInputs = [ pigz ];
@ -461,40 +468,45 @@ rec {
# 4. compute the layer id
# 5. put the layer in the image
# 6. repack the image
buildImage = args@{
buildImage =
args@{
# Image name.
name,
# Image tag, when null then the nix output hash will be used.
tag ? null,
# Parent image, to append to.
fromImage ? null,
# Name of the parent image; will be read from the image otherwise.
fromImageName ? null,
# Tag of the parent image; will be read from the image otherwise.
fromImageTag ? null,
# Files to put on the image (a nix store path or list of paths).
contents ? null,
# When copying the contents into the image, preserve symlinks to
name
, # Image tag, when null then the nix output hash will be used.
tag ? null
, # Parent image, to append to.
fromImage ? null
, # Name of the parent image; will be read from the image otherwise.
fromImageName ? null
, # Tag of the parent image; will be read from the image otherwise.
fromImageTag ? null
, # Files to put on the image (a nix store path or list of paths).
contents ? null
, # When copying the contents into the image, preserve symlinks to
# directories (see `rsync -K`). Otherwise, transform those symlinks
# into directories.
keepContentsDirlinks ? false,
# Docker config; e.g. what command to run on the container.
config ? null,
# Optional bash script to run on the files prior to fixturizing the layer.
extraCommands ? "", uid ? 0, gid ? 0,
# Optional bash script to run as root on the image when provisioning.
runAsRoot ? null,
# Size of the virtual machine disk to provision when building the image.
diskSize ? 1024,
# Time of creation of the image.
created ? "1970-01-01T00:00:01Z",
keepContentsDirlinks ? false
, # Docker config; e.g. what command to run on the container.
config ? null
, # Optional bash script to run on the files prior to fixturizing the layer.
extraCommands ? ""
, uid ? 0
, gid ? 0
, # Optional bash script to run as root on the image when provisioning.
runAsRoot ? null
, # Size of the virtual machine disk to provision when building the image.
diskSize ? 1024
, # Time of creation of the image.
created ? "1970-01-01T00:00:01Z"
,
}:
let
baseName = baseNameOf name;
# Create a JSON blob of the configuration. Set the date to unix zero.
baseJson = let
baseJson =
let
pure = writeText "${baseName}-config.json" (builtins.toJSON {
inherit created config;
architecture = defaultArch;
@ -505,20 +517,25 @@ rec {
''
jq ".created = \"$(TZ=utc date --iso-8601="seconds")\"" ${pure} > $out
'';
in if created == "now" then impure else pure;
in
if created == "now" then impure else pure;
layer =
if runAsRoot == null
then mkPureLayer {
then
mkPureLayer
{
name = baseName;
inherit baseJson contents keepContentsDirlinks extraCommands uid gid;
} else mkRootLayer {
} else
mkRootLayer {
name = baseName;
inherit baseJson fromImage fromImageName fromImageTag
contents keepContentsDirlinks runAsRoot diskSize
extraCommands;
};
result = runCommand "docker-image-${baseName}.tar.gz" {
result = runCommand "docker-image-${baseName}.tar.gz"
{
nativeBuildInputs = [ jshon pigz coreutils findutils jq moreutils ];
# Image name must be lowercase
imageName = lib.toLower name;
@ -732,14 +749,14 @@ rec {
root:x:0:
nobody:x:65534:
'')
(runCommand "var-empty" {} ''
(runCommand "var-empty" { } ''
mkdir -p $out/var/empty
'')
];
};
# This provides /bin/sh, pointing to bashInteractive.
binSh = runCommand "bin-sh" {} ''
binSh = runCommand "bin-sh" { } ''
mkdir -p $out/bin
ln -s ${bashInteractive}/bin/bash $out/bin/sh
'';
@ -760,32 +777,34 @@ rec {
})
);
streamLayeredImage = {
streamLayeredImage =
{
# Image Name
name,
# Image tag, the Nix's output hash will be used if null
tag ? null,
# Parent image, to append to.
fromImage ? null,
# Files to put on the image (a nix store path or list of paths).
contents ? [],
# Docker config; e.g. what command to run on the container.
config ? {},
# Time of creation of the image. Passing "now" will make the
name
, # Image tag, the Nix's output hash will be used if null
tag ? null
, # Parent image, to append to.
fromImage ? null
, # Files to put on the image (a nix store path or list of paths).
contents ? [ ]
, # Docker config; e.g. what command to run on the container.
config ? { }
, # Time of creation of the image. Passing "now" will make the
# created date be the time of building.
created ? "1970-01-01T00:00:01Z",
# Optional bash script to run on the files prior to fixturizing the layer.
extraCommands ? "",
# Optional bash script to run inside fakeroot environment.
created ? "1970-01-01T00:00:01Z"
, # Optional bash script to run on the files prior to fixturizing the layer.
extraCommands ? ""
, # Optional bash script to run inside fakeroot environment.
# Could be used for changing ownership of files in customisation layer.
fakeRootCommands ? "",
# We pick 100 to ensure there is plenty of room for extension. I
fakeRootCommands ? ""
, # We pick 100 to ensure there is plenty of room for extension. I
# believe the actual maximum is 128.
maxLayers ? 100,
# Whether to include store paths in the image. You generally want to leave
maxLayers ? 100
, # Whether to include store paths in the image. You generally want to leave
# this on, but tooling may disable this to insert the store paths more
# efficiently via other means, such as bind mounting the host store.
includeStorePaths ? true,
includeStorePaths ? true
,
}:
assert
(lib.assertMsg (maxLayers > 1)
@ -793,7 +812,7 @@ rec {
let
baseName = baseNameOf name;
streamScript = writePython3 "stream" {} ./stream_layered_image.py;
streamScript = writePython3 "stream" { } ./stream_layered_image.py;
baseJson = writeText "${baseName}-base.json" (builtins.toJSON {
inherit config;
architecture = defaultArch;
@ -833,7 +852,7 @@ rec {
'';
};
closureRoots = optionals includeStorePaths /* normally true */ (
closureRoots = lib.optionals includeStorePaths /* normally true */ (
[ baseJson ] ++ contentsList
);
overallClosure = writeText "closure" (lib.concatStringsSep " " closureRoots);
@ -842,7 +861,8 @@ rec {
# so they'll be excluded from the created images.
unnecessaryDrvs = [ baseJson overallClosure ];
conf = runCommand "${baseName}-conf.json" {
conf = runCommand "${baseName}-conf.json"
{
inherit fromImage maxLayers created;
imageName = lib.toLower name;
passthru.imageTag =
@ -931,7 +951,8 @@ rec {
--arg created "$created" |
tee $out
'';
result = runCommand "stream-${baseName}" {
result = runCommand "stream-${baseName}"
{
inherit (conf) imageName;
passthru = {
inherit (conf) imageTag;
@ -944,5 +965,6 @@ rec {
} ''
makeWrapper ${streamScript} $out --add-flags ${conf}
'';
in result;
in
result;
}