2024-05-02 00:46:19 +00:00
|
|
|
# Examples of using the docker tools to build packages.
|
|
|
|
#
|
|
|
|
# This file defines several docker images. In order to use an image,
|
|
|
|
# build its derivation with `nix-build`, and then load the result with
|
|
|
|
# `docker load`. For example:
|
|
|
|
#
|
|
|
|
# $ nix-build '<nixpkgs>' -A dockerTools.examples.redis
|
|
|
|
# $ docker load < result
|
|
|
|
|
2024-06-30 08:16:52 +00:00
|
|
|
{
|
|
|
|
pkgs,
|
|
|
|
buildImage,
|
|
|
|
buildLayeredImage,
|
|
|
|
fakeNss,
|
|
|
|
pullImage,
|
|
|
|
shadowSetup,
|
|
|
|
buildImageWithNixDb,
|
|
|
|
pkgsCross,
|
|
|
|
streamNixShellImage,
|
|
|
|
}:
|
2024-05-02 00:46:19 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
nixosLib = import ../../../nixos/lib {
|
|
|
|
# Experimental features need testing too, but there's no point in warning
|
|
|
|
# about it, so we enable the feature flag.
|
2024-06-30 08:16:52 +00:00
|
|
|
featureFlags.minimalModules = { };
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; };
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
|
|
rec {
|
|
|
|
# 1. basic example
|
|
|
|
bash = buildImage {
|
|
|
|
name = "bash";
|
|
|
|
tag = "latest";
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
paths = [ pkgs.bashInteractive ];
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 2. service example, layered on another image
|
|
|
|
redis = buildImage {
|
|
|
|
name = "redis";
|
|
|
|
tag = "latest";
|
|
|
|
|
|
|
|
# for example's sake, we can layer redis on top of bash or debian
|
|
|
|
fromImage = bash;
|
|
|
|
# fromImage = debian;
|
|
|
|
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
paths = [ pkgs.redis ];
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
};
|
|
|
|
|
|
|
|
runAsRoot = ''
|
|
|
|
mkdir -p /data
|
|
|
|
'';
|
|
|
|
|
|
|
|
config = {
|
|
|
|
Cmd = [ "/bin/redis-server" ];
|
|
|
|
WorkingDir = "/data";
|
|
|
|
Volumes = {
|
2024-06-30 08:16:52 +00:00
|
|
|
"/data" = { };
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 3. another service example
|
2024-06-30 08:16:52 +00:00
|
|
|
nginx =
|
|
|
|
let
|
|
|
|
nginxPort = "80";
|
|
|
|
nginxConf = pkgs.writeText "nginx.conf" ''
|
|
|
|
user nobody nobody;
|
|
|
|
daemon off;
|
|
|
|
error_log /dev/stdout info;
|
|
|
|
pid /dev/null;
|
|
|
|
events {}
|
|
|
|
http {
|
|
|
|
access_log /dev/stdout;
|
|
|
|
server {
|
|
|
|
listen ${nginxPort};
|
|
|
|
index index.html;
|
|
|
|
location / {
|
|
|
|
root ${nginxWebRoot};
|
|
|
|
}
|
2024-05-02 00:46:19 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-30 08:16:52 +00:00
|
|
|
'';
|
|
|
|
nginxWebRoot = pkgs.writeTextDir "index.html" ''
|
|
|
|
<html><body><h1>Hello from NGINX</h1></body></html>
|
|
|
|
'';
|
|
|
|
in
|
|
|
|
buildLayeredImage {
|
|
|
|
name = "nginx-container";
|
|
|
|
tag = "latest";
|
|
|
|
contents = [
|
|
|
|
fakeNss
|
|
|
|
pkgs.nginx
|
|
|
|
];
|
2024-05-02 00:46:19 +00:00
|
|
|
|
2024-06-30 08:16:52 +00:00
|
|
|
extraCommands = ''
|
|
|
|
mkdir -p tmp/nginx_client_body
|
2024-05-02 00:46:19 +00:00
|
|
|
|
2024-06-30 08:16:52 +00:00
|
|
|
# nginx still tries to read this directory even if error_log
|
|
|
|
# directive is specifying another file :/
|
|
|
|
mkdir -p var/log/nginx
|
|
|
|
'';
|
2024-05-02 00:46:19 +00:00
|
|
|
|
2024-06-30 08:16:52 +00:00
|
|
|
config = {
|
|
|
|
Cmd = [
|
|
|
|
"nginx"
|
|
|
|
"-c"
|
|
|
|
nginxConf
|
|
|
|
];
|
|
|
|
ExposedPorts = {
|
|
|
|
"${nginxPort}/tcp" = { };
|
|
|
|
};
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 4. example of pulling an image. could be used as a base for other images
|
|
|
|
nixFromDockerHub = pullImage {
|
|
|
|
imageName = "nixos/nix";
|
|
|
|
imageDigest = "sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357";
|
|
|
|
sha256 = "19fw0n3wmddahzr20mhdqv6jkjn1kanh6n2mrr08ai53dr8ph5n7";
|
|
|
|
finalImageTag = "2.2.1";
|
|
|
|
finalImageName = "nix";
|
|
|
|
};
|
|
|
|
# Same example, but re-fetches every time the fetcher implementation changes.
|
|
|
|
# NOTE: Only use this for testing, or you'd be wasting a lot of time, network and space.
|
|
|
|
testNixFromDockerHub = pkgs.testers.invalidateFetcherByDrvHash pullImage {
|
|
|
|
imageName = "nixos/nix";
|
|
|
|
imageDigest = "sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357";
|
|
|
|
sha256 = "19fw0n3wmddahzr20mhdqv6jkjn1kanh6n2mrr08ai53dr8ph5n7";
|
|
|
|
finalImageTag = "2.2.1";
|
|
|
|
finalImageName = "nix";
|
|
|
|
};
|
|
|
|
|
|
|
|
# 5. example of multiple contents, emacs and vi happily coexisting
|
|
|
|
editors = buildImage {
|
|
|
|
name = "editors";
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [
|
|
|
|
pkgs.coreutils
|
|
|
|
pkgs.bash
|
|
|
|
pkgs.emacs
|
|
|
|
pkgs.vim
|
|
|
|
pkgs.nano
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 6. nix example to play with the container nix store
|
|
|
|
# docker run -it --rm nix nix-store -qR $(nix-build '<nixpkgs>' -A nix)
|
|
|
|
nix = buildImageWithNixDb {
|
|
|
|
name = "nix";
|
|
|
|
tag = "latest";
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [
|
|
|
|
# nix-store uses cat program to display results as specified by
|
|
|
|
# the image env variable NIX_PAGER.
|
|
|
|
pkgs.coreutils
|
|
|
|
pkgs.nix
|
|
|
|
pkgs.bash
|
|
|
|
];
|
|
|
|
};
|
|
|
|
config = {
|
|
|
|
Env = [
|
|
|
|
"NIX_PAGER=cat"
|
|
|
|
# A user is required by nix
|
|
|
|
# https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
|
|
|
|
"USER=nobody"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 7. example of adding something on top of an image pull by our
|
|
|
|
# dockerTools chain.
|
|
|
|
onTopOfPulledImage = buildImage {
|
|
|
|
name = "onTopOfPulledImage";
|
|
|
|
tag = "latest";
|
|
|
|
fromImage = nixFromDockerHub;
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [ pkgs.hello ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 8. regression test for erroneous use of eval and string expansion.
|
|
|
|
# See issue #34779 and PR #40947 for details.
|
|
|
|
runAsRootExtraCommands = pkgs.dockerTools.buildImage {
|
|
|
|
name = "runAsRootExtraCommands";
|
|
|
|
tag = "latest";
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [ pkgs.coreutils ];
|
|
|
|
};
|
|
|
|
# The parens here are to create problematic bash to embed and eval. In case
|
|
|
|
# this is *embedded* into the script (with nix expansion) the initial quotes
|
|
|
|
# will close the string and the following parens are unexpected
|
|
|
|
runAsRoot = ''echo "(runAsRoot)" > runAsRoot'';
|
|
|
|
extraCommands = ''echo "(extraCommand)" > extraCommands'';
|
|
|
|
};
|
|
|
|
|
|
|
|
# 9. Ensure that setting created to now results in a date which
|
|
|
|
# isn't the epoch + 1
|
|
|
|
unstableDate = pkgs.dockerTools.buildImage {
|
|
|
|
name = "unstable-date";
|
|
|
|
tag = "latest";
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [ pkgs.coreutils ];
|
|
|
|
};
|
|
|
|
created = "now";
|
|
|
|
};
|
|
|
|
|
|
|
|
# 10. Create a layered image
|
|
|
|
layered-image = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "layered-image";
|
|
|
|
tag = "latest";
|
|
|
|
extraCommands = ''echo "(extraCommand)" > extraCommands'';
|
|
|
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
2024-06-30 08:16:52 +00:00
|
|
|
contents = [
|
|
|
|
pkgs.hello
|
|
|
|
pkgs.bash
|
|
|
|
pkgs.coreutils
|
|
|
|
];
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# 11. Create an image on top of a layered image
|
|
|
|
layered-on-top = pkgs.dockerTools.buildImage {
|
|
|
|
name = "layered-on-top";
|
|
|
|
tag = "latest";
|
|
|
|
fromImage = layered-image;
|
|
|
|
extraCommands = ''
|
|
|
|
mkdir ./example-output
|
|
|
|
chmod 777 ./example-output
|
|
|
|
'';
|
|
|
|
config = {
|
|
|
|
Env = [ "PATH=${pkgs.coreutils}/bin/" ];
|
|
|
|
WorkingDir = "/example-output";
|
|
|
|
Cmd = [
|
2024-06-30 08:16:52 +00:00
|
|
|
"${pkgs.bash}/bin/bash"
|
|
|
|
"-c"
|
|
|
|
"echo hello > foo; cat foo"
|
2024-05-02 00:46:19 +00:00
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 12 Create a layered image on top of a layered image
|
|
|
|
layered-on-top-layered = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "layered-on-top-layered";
|
|
|
|
tag = "latest";
|
|
|
|
fromImage = layered-image;
|
|
|
|
extraCommands = ''
|
|
|
|
mkdir ./example-output
|
|
|
|
chmod 777 ./example-output
|
|
|
|
'';
|
|
|
|
config = {
|
|
|
|
Env = [ "PATH=${pkgs.coreutils}/bin/" ];
|
|
|
|
WorkingDir = "/example-output";
|
|
|
|
Cmd = [
|
2024-06-30 08:16:52 +00:00
|
|
|
"${pkgs.bash}/bin/bash"
|
|
|
|
"-c"
|
|
|
|
"echo hello > foo; cat foo"
|
2024-05-02 00:46:19 +00:00
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 13. example of running something as root on top of a parent image
|
|
|
|
# Regression test related to PR #52109
|
|
|
|
runAsRootParentImage = buildImage {
|
|
|
|
name = "runAsRootParentImage";
|
|
|
|
tag = "latest";
|
|
|
|
runAsRoot = "touch /example-file";
|
|
|
|
fromImage = bash;
|
|
|
|
};
|
|
|
|
|
|
|
|
# 14. example of 3 layers images This image is used to verify the
|
|
|
|
# order of layers is correct.
|
|
|
|
# It allows to validate
|
|
|
|
# - the layer of parent are below
|
|
|
|
# - the order of parent layer is preserved at image build time
|
|
|
|
# (this is why there are 3 images)
|
2024-06-30 08:16:52 +00:00
|
|
|
layersOrder =
|
|
|
|
let
|
|
|
|
l1 = pkgs.dockerTools.buildImage {
|
|
|
|
name = "l1";
|
|
|
|
tag = "latest";
|
|
|
|
extraCommands = ''
|
|
|
|
mkdir -p tmp
|
|
|
|
echo layer1 > tmp/layer1
|
|
|
|
echo layer1 > tmp/layer2
|
|
|
|
echo layer1 > tmp/layer3
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
l2 = pkgs.dockerTools.buildImage {
|
|
|
|
name = "l2";
|
|
|
|
fromImage = l1;
|
|
|
|
tag = "latest";
|
|
|
|
extraCommands = ''
|
|
|
|
mkdir -p tmp
|
|
|
|
echo layer2 > tmp/layer2
|
|
|
|
echo layer2 > tmp/layer3
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
in
|
|
|
|
pkgs.dockerTools.buildImage {
|
|
|
|
name = "l3";
|
|
|
|
fromImage = l2;
|
2024-05-02 00:46:19 +00:00
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [ pkgs.coreutils ];
|
|
|
|
};
|
2024-05-02 00:46:19 +00:00
|
|
|
extraCommands = ''
|
|
|
|
mkdir -p tmp
|
2024-06-30 08:16:52 +00:00
|
|
|
echo layer3 > tmp/layer3
|
2024-05-02 00:46:19 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
# 15. Environment variable inheritance.
|
|
|
|
# Child image should inherit parents environment variables,
|
|
|
|
# optionally overriding them.
|
|
|
|
environmentVariablesParent = pkgs.dockerTools.buildImage {
|
|
|
|
name = "parent";
|
|
|
|
tag = "latest";
|
|
|
|
config = {
|
|
|
|
Env = [
|
|
|
|
"FROM_PARENT=true"
|
|
|
|
"LAST_LAYER=parent"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
environmentVariables = pkgs.dockerTools.buildImage {
|
|
|
|
name = "child";
|
|
|
|
fromImage = environmentVariablesParent;
|
|
|
|
tag = "latest";
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [ pkgs.coreutils ];
|
|
|
|
};
|
|
|
|
config = {
|
|
|
|
Env = [
|
|
|
|
"FROM_CHILD=true"
|
|
|
|
"LAST_LAYER=child"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
environmentVariablesLayered = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "child";
|
|
|
|
fromImage = environmentVariablesParent;
|
|
|
|
tag = "latest";
|
|
|
|
contents = [ pkgs.coreutils ];
|
|
|
|
config = {
|
|
|
|
Env = [
|
|
|
|
"FROM_CHILD=true"
|
|
|
|
"LAST_LAYER=child"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 16. Create another layered image, for comparing layers with image 10.
|
|
|
|
another-layered-image = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "another-layered-image";
|
|
|
|
tag = "latest";
|
|
|
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
|
|
|
};
|
|
|
|
|
|
|
|
# 17. Create a layered image with only 2 layers
|
|
|
|
two-layered-image = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "two-layered-image";
|
|
|
|
tag = "latest";
|
|
|
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
2024-06-30 08:16:52 +00:00
|
|
|
contents = [
|
|
|
|
pkgs.bash
|
|
|
|
pkgs.hello
|
|
|
|
];
|
2024-05-02 00:46:19 +00:00
|
|
|
maxLayers = 2;
|
|
|
|
};
|
|
|
|
|
|
|
|
# 18. Create a layered image with more packages than max layers.
|
|
|
|
# coreutils and hello are part of the same layer
|
|
|
|
bulk-layer = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "bulk-layer";
|
|
|
|
tag = "latest";
|
|
|
|
contents = with pkgs; [
|
2024-06-30 08:16:52 +00:00
|
|
|
coreutils
|
|
|
|
hello
|
2024-05-02 00:46:19 +00:00
|
|
|
];
|
|
|
|
maxLayers = 2;
|
|
|
|
};
|
|
|
|
|
|
|
|
# 19. Create a layered image with a base image and more packages than max
|
|
|
|
# layers. coreutils and hello are part of the same layer
|
|
|
|
layered-bulk-layer = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "layered-bulk-layer";
|
|
|
|
tag = "latest";
|
|
|
|
fromImage = two-layered-image;
|
|
|
|
contents = with pkgs; [
|
2024-06-30 08:16:52 +00:00
|
|
|
coreutils
|
|
|
|
hello
|
2024-05-02 00:46:19 +00:00
|
|
|
];
|
|
|
|
maxLayers = 4;
|
|
|
|
};
|
|
|
|
|
|
|
|
# 20. Create a "layered" image without nix store layers. This is not
|
|
|
|
# recommended, but can be useful for base images in rare cases.
|
|
|
|
no-store-paths = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "no-store-paths";
|
|
|
|
tag = "latest";
|
|
|
|
extraCommands = ''
|
|
|
|
# This removes sharing of busybox and is not recommended. We do this
|
|
|
|
# to make the example suitable as a test case with working binaries.
|
|
|
|
cp -r ${pkgs.pkgsStatic.busybox}/* .
|
|
|
|
|
|
|
|
# This is a "build" dependency that will not appear in the image
|
|
|
|
${pkgs.hello}/bin/hello
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
nixLayered = pkgs.dockerTools.buildLayeredImageWithNixDb {
|
|
|
|
name = "nix-layered";
|
|
|
|
tag = "latest";
|
|
|
|
contents = [
|
|
|
|
# nix-store uses cat program to display results as specified by
|
|
|
|
# the image env variable NIX_PAGER.
|
|
|
|
pkgs.coreutils
|
|
|
|
pkgs.nix
|
|
|
|
pkgs.bash
|
|
|
|
];
|
|
|
|
config = {
|
|
|
|
Env = [
|
|
|
|
"NIX_PAGER=cat"
|
|
|
|
# A user is required by nix
|
|
|
|
# https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
|
|
|
|
"USER=nobody"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 21. Support files in the store on buildLayeredImage
|
|
|
|
# See: https://github.com/NixOS/nixpkgs/pull/91084#issuecomment-653496223
|
|
|
|
filesInStore = pkgs.dockerTools.buildLayeredImageWithNixDb {
|
|
|
|
name = "file-in-store";
|
|
|
|
tag = "latest";
|
|
|
|
contents = [
|
|
|
|
pkgs.coreutils
|
|
|
|
pkgs.nix
|
|
|
|
(pkgs.writeScriptBin "myscript" ''
|
|
|
|
#!${pkgs.runtimeShell}
|
|
|
|
cat ${pkgs.writeText "somefile" "some data"}
|
|
|
|
'')
|
|
|
|
];
|
|
|
|
config = {
|
|
|
|
Cmd = [ "myscript" ];
|
|
|
|
# For some reason 'nix-store --verify' requires this environment variable
|
|
|
|
Env = [ "USER=root" ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# 22. Ensure that setting created to now results in a date which
|
|
|
|
# isn't the epoch + 1 for layered images.
|
|
|
|
unstableDateLayered = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "unstable-date-layered";
|
|
|
|
tag = "latest";
|
|
|
|
contents = [ pkgs.coreutils ];
|
|
|
|
created = "now";
|
|
|
|
};
|
|
|
|
|
|
|
|
# 23. Ensure that layers are unpacked in the correct order before the
|
|
|
|
# runAsRoot script is executed.
|
|
|
|
layersUnpackOrder =
|
2024-06-30 08:16:52 +00:00
|
|
|
let
|
|
|
|
layerOnTopOf =
|
|
|
|
parent: layerName:
|
|
|
|
pkgs.dockerTools.buildImage {
|
|
|
|
name = "layers-unpack-order-${layerName}";
|
|
|
|
tag = "latest";
|
|
|
|
fromImage = parent;
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [ pkgs.coreutils ];
|
|
|
|
};
|
|
|
|
runAsRoot = ''
|
|
|
|
#!${pkgs.runtimeShell}
|
|
|
|
echo -n "${layerName}" >> /layer-order
|
|
|
|
'';
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
2024-06-30 08:16:52 +00:00
|
|
|
# When executing the runAsRoot script when building layer C, if layer B is
|
|
|
|
# not unpacked on top of layer A, the contents of /layer-order will not be
|
|
|
|
# "ABC".
|
|
|
|
layerA = layerOnTopOf null "a";
|
|
|
|
layerB = layerOnTopOf layerA "b";
|
|
|
|
layerC = layerOnTopOf layerB "c";
|
|
|
|
in
|
|
|
|
layerC;
|
2024-05-02 00:46:19 +00:00
|
|
|
|
|
|
|
bashUncompressed = pkgs.dockerTools.buildImage {
|
|
|
|
name = "bash-uncompressed";
|
|
|
|
tag = "latest";
|
|
|
|
compressor = "none";
|
|
|
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
|
|
|
copyToRoot = pkgs.bashInteractive;
|
|
|
|
};
|
|
|
|
|
|
|
|
bashZstdCompressed = pkgs.dockerTools.buildImage {
|
|
|
|
name = "bash-zstd";
|
|
|
|
tag = "latest";
|
|
|
|
compressor = "zstd";
|
|
|
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
|
|
|
copyToRoot = pkgs.bashInteractive;
|
|
|
|
};
|
|
|
|
|
|
|
|
# buildImage without explicit tag
|
|
|
|
bashNoTag = pkgs.dockerTools.buildImage {
|
|
|
|
name = "bash-no-tag";
|
|
|
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
|
|
|
copyToRoot = pkgs.bashInteractive;
|
|
|
|
};
|
|
|
|
|
|
|
|
# buildLayeredImage without explicit tag
|
|
|
|
bashNoTagLayered = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "bash-no-tag-layered";
|
|
|
|
contents = pkgs.bashInteractive;
|
|
|
|
};
|
|
|
|
|
|
|
|
# buildLayeredImage without compression
|
|
|
|
bashLayeredUncompressed = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "bash-layered-uncompressed";
|
|
|
|
tag = "latest";
|
|
|
|
compressor = "none";
|
|
|
|
contents = pkgs.bashInteractive;
|
|
|
|
};
|
|
|
|
|
|
|
|
# buildLayeredImage with zstd compression
|
|
|
|
bashLayeredZstdCompressed = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "bash-layered-zstd";
|
|
|
|
tag = "latest";
|
|
|
|
compressor = "zstd";
|
|
|
|
contents = pkgs.bashInteractive;
|
|
|
|
};
|
|
|
|
|
|
|
|
# streamLayeredImage without explicit tag
|
|
|
|
bashNoTagStreamLayered = pkgs.dockerTools.streamLayeredImage {
|
|
|
|
name = "bash-no-tag-stream-layered";
|
|
|
|
contents = pkgs.bashInteractive;
|
|
|
|
};
|
|
|
|
|
|
|
|
# buildLayeredImage with non-root user
|
|
|
|
bashLayeredWithUser =
|
2024-06-30 08:16:52 +00:00
|
|
|
let
|
|
|
|
nonRootShadowSetup =
|
|
|
|
{
|
|
|
|
user,
|
|
|
|
uid,
|
|
|
|
gid ? uid,
|
|
|
|
}:
|
|
|
|
with pkgs;
|
|
|
|
[
|
|
|
|
(writeTextDir "etc/shadow" ''
|
|
|
|
root:!x:::::::
|
|
|
|
${user}:!:::::::
|
|
|
|
'')
|
|
|
|
(writeTextDir "etc/passwd" ''
|
|
|
|
root:x:0:0::/root:${runtimeShell}
|
|
|
|
${user}:x:${toString uid}:${toString gid}::/home/${user}:
|
|
|
|
'')
|
|
|
|
(writeTextDir "etc/group" ''
|
|
|
|
root:x:0:
|
|
|
|
${user}:x:${toString gid}:
|
|
|
|
'')
|
|
|
|
(writeTextDir "etc/gshadow" ''
|
|
|
|
root:x::
|
|
|
|
${user}:x::
|
|
|
|
'')
|
|
|
|
];
|
|
|
|
in
|
2024-05-02 00:46:19 +00:00
|
|
|
pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "bash-layered-with-user";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
contents =
|
|
|
|
[
|
|
|
|
pkgs.bash
|
|
|
|
pkgs.coreutils
|
|
|
|
]
|
|
|
|
++ nonRootShadowSetup {
|
|
|
|
uid = 999;
|
|
|
|
user = "somebody";
|
|
|
|
};
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# basic example, with cross compilation
|
2024-06-30 08:16:52 +00:00
|
|
|
cross =
|
|
|
|
let
|
|
|
|
# Cross compile for x86_64 if on aarch64
|
|
|
|
crossPkgs =
|
|
|
|
if pkgs.stdenv.hostPlatform.system == "aarch64-linux" then
|
|
|
|
pkgsCross.gnu64
|
|
|
|
else
|
|
|
|
pkgsCross.aarch64-multiplatform;
|
|
|
|
in
|
|
|
|
crossPkgs.dockerTools.buildImage {
|
|
|
|
name = "hello-cross";
|
|
|
|
tag = "latest";
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-root";
|
|
|
|
pathsToLink = [ "/bin" ];
|
|
|
|
paths = [ crossPkgs.hello ];
|
|
|
|
};
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# layered image where a store path is itself a symlink
|
|
|
|
layeredStoreSymlink =
|
2024-06-30 08:16:52 +00:00
|
|
|
let
|
|
|
|
target = pkgs.writeTextDir "dir/target" "Content doesn't matter.";
|
|
|
|
symlink = pkgs.runCommand "symlink" { } "ln -s ${target} $out";
|
|
|
|
in
|
2024-05-02 00:46:19 +00:00
|
|
|
pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "layeredstoresymlink";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
contents = [
|
|
|
|
pkgs.bash
|
|
|
|
symlink
|
|
|
|
];
|
|
|
|
}
|
|
|
|
// {
|
|
|
|
passthru = {
|
|
|
|
inherit symlink;
|
|
|
|
};
|
|
|
|
};
|
2024-05-02 00:46:19 +00:00
|
|
|
|
|
|
|
# image with registry/ prefix
|
|
|
|
prefixedImage = pkgs.dockerTools.buildImage {
|
|
|
|
name = "registry-1.docker.io/image";
|
|
|
|
tag = "latest";
|
|
|
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
|
|
|
};
|
|
|
|
|
|
|
|
# layered image with registry/ prefix
|
|
|
|
prefixedLayeredImage = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "registry-1.docker.io/layered-image";
|
|
|
|
tag = "latest";
|
|
|
|
config.Cmd = [ "${pkgs.hello}/bin/hello" ];
|
|
|
|
};
|
|
|
|
|
|
|
|
# layered image with files owned by a user other than root
|
|
|
|
layeredImageWithFakeRootCommands = pkgs.dockerTools.buildLayeredImage {
|
|
|
|
name = "layered-image-with-fake-root-commands";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
contents = [ pkgs.pkgsStatic.busybox ];
|
2024-05-02 00:46:19 +00:00
|
|
|
fakeRootCommands = ''
|
|
|
|
mkdir -p ./home/alice
|
|
|
|
chown 1000 ./home/alice
|
2024-06-30 08:16:52 +00:00
|
|
|
ln -s ${
|
|
|
|
pkgs.hello.overrideAttrs (o: {
|
|
|
|
# A unique `hello` to make sure that it isn't included via another mechanism by accident.
|
|
|
|
configureFlags = o.configureFlags or [ ] ++ [
|
|
|
|
" --program-prefix=layeredImageWithFakeRootCommands-"
|
|
|
|
];
|
|
|
|
doCheck = false;
|
|
|
|
})
|
|
|
|
} ./hello
|
2024-05-02 00:46:19 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
# tarball consisting of both bash and redis images
|
|
|
|
mergedBashAndRedis = pkgs.dockerTools.mergeImages [
|
|
|
|
bash
|
|
|
|
redis
|
|
|
|
];
|
|
|
|
|
|
|
|
# tarball consisting of bash (without tag) and redis images
|
|
|
|
mergedBashNoTagAndRedis = pkgs.dockerTools.mergeImages [
|
|
|
|
bashNoTag
|
|
|
|
redis
|
|
|
|
];
|
|
|
|
|
|
|
|
# tarball consisting of bash and layered image with different owner of the
|
|
|
|
# /home/alice directory
|
|
|
|
mergedBashFakeRoot = pkgs.dockerTools.mergeImages [
|
|
|
|
bash
|
|
|
|
layeredImageWithFakeRootCommands
|
|
|
|
];
|
|
|
|
|
|
|
|
mergeVaryingCompressor = pkgs.dockerTools.mergeImages [
|
|
|
|
redis
|
|
|
|
bashUncompressed
|
|
|
|
bashZstdCompressed
|
|
|
|
];
|
|
|
|
|
|
|
|
helloOnRoot = pkgs.dockerTools.streamLayeredImage {
|
|
|
|
name = "hello";
|
|
|
|
tag = "latest";
|
|
|
|
contents = [
|
|
|
|
(pkgs.buildEnv {
|
|
|
|
name = "hello-root";
|
|
|
|
paths = [ pkgs.hello ];
|
|
|
|
})
|
|
|
|
];
|
|
|
|
config.Cmd = [ "hello" ];
|
|
|
|
};
|
|
|
|
|
|
|
|
helloOnRootNoStore = pkgs.dockerTools.streamLayeredImage {
|
|
|
|
name = "hello";
|
|
|
|
tag = "latest";
|
|
|
|
contents = [
|
|
|
|
(pkgs.buildEnv {
|
|
|
|
name = "hello-root";
|
|
|
|
paths = [ pkgs.hello ];
|
|
|
|
})
|
|
|
|
];
|
|
|
|
config.Cmd = [ "hello" ];
|
|
|
|
includeStorePaths = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
helloOnRootNoStoreFakechroot = pkgs.dockerTools.streamLayeredImage {
|
|
|
|
name = "hello";
|
|
|
|
tag = "latest";
|
|
|
|
contents = [
|
|
|
|
(pkgs.buildEnv {
|
|
|
|
name = "hello-root";
|
|
|
|
paths = [ pkgs.hello ];
|
|
|
|
})
|
|
|
|
];
|
|
|
|
config.Cmd = [ "hello" ];
|
|
|
|
includeStorePaths = false;
|
|
|
|
enableFakechroot = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
etc =
|
|
|
|
let
|
|
|
|
inherit (pkgs) lib;
|
2024-06-30 08:16:52 +00:00
|
|
|
nixosCore = (
|
|
|
|
evalMinimalConfig (
|
|
|
|
{ config, ... }:
|
|
|
|
{
|
|
|
|
imports = [
|
|
|
|
pkgs.pkgsModule
|
|
|
|
../../../nixos/modules/system/etc/etc.nix
|
|
|
|
];
|
|
|
|
environment.etc."some-config-file" = {
|
|
|
|
text = ''
|
|
|
|
127.0.0.1 localhost
|
|
|
|
::1 localhost
|
|
|
|
'';
|
|
|
|
# For executables:
|
|
|
|
# mode = "0755";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
in
|
|
|
|
pkgs.dockerTools.streamLayeredImage {
|
2024-05-02 00:46:19 +00:00
|
|
|
name = "etc";
|
|
|
|
tag = "latest";
|
|
|
|
enableFakechroot = true;
|
|
|
|
fakeRootCommands = ''
|
|
|
|
mkdir -p /etc
|
|
|
|
${nixosCore.config.system.build.etcActivationCommands}
|
|
|
|
'';
|
|
|
|
config.Cmd = pkgs.writeScript "etc-cmd" ''
|
|
|
|
#!${pkgs.busybox}/bin/sh
|
|
|
|
${pkgs.busybox}/bin/cat /etc/some-config-file
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
# Example export of the bash image
|
|
|
|
exportBash = pkgs.dockerTools.exportImage { fromImage = bash; };
|
|
|
|
|
|
|
|
imageViaFakeChroot = pkgs.dockerTools.streamLayeredImage {
|
|
|
|
name = "image-via-fake-chroot";
|
|
|
|
tag = "latest";
|
|
|
|
config.Cmd = [ "hello" ];
|
|
|
|
enableFakechroot = true;
|
|
|
|
# Crucially, instead of a relative path, this creates /bin, which is
|
|
|
|
# intercepted by fakechroot.
|
|
|
|
# This functionality is not available on darwin as of 2021.
|
|
|
|
fakeRootCommands = ''
|
|
|
|
mkdir /bin
|
|
|
|
ln -s ${pkgs.hello}/bin/hello /bin/hello
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
build-image-with-path = buildImage {
|
|
|
|
name = "build-image-with-path";
|
|
|
|
tag = "latest";
|
|
|
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
2024-06-30 08:16:52 +00:00
|
|
|
copyToRoot = [
|
|
|
|
pkgs.bashInteractive
|
|
|
|
./test-dummy
|
|
|
|
];
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
layered-image-with-path = pkgs.dockerTools.streamLayeredImage {
|
|
|
|
name = "layered-image-with-path";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
contents = [
|
|
|
|
pkgs.bashInteractive
|
|
|
|
./test-dummy
|
|
|
|
];
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
build-image-with-architecture = buildImage {
|
|
|
|
name = "build-image-with-architecture";
|
|
|
|
tag = "latest";
|
|
|
|
architecture = "arm64";
|
|
|
|
# Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
|
2024-06-30 08:16:52 +00:00
|
|
|
copyToRoot = [
|
|
|
|
pkgs.bashInteractive
|
|
|
|
./test-dummy
|
|
|
|
];
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
layered-image-with-architecture = pkgs.dockerTools.streamLayeredImage {
|
|
|
|
name = "layered-image-with-architecture";
|
|
|
|
tag = "latest";
|
|
|
|
architecture = "arm64";
|
2024-06-30 08:16:52 +00:00
|
|
|
contents = [
|
|
|
|
pkgs.bashInteractive
|
|
|
|
./test-dummy
|
|
|
|
];
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# ensure that caCertificates builds
|
|
|
|
image-with-certs = buildImage {
|
|
|
|
name = "image-with-certs";
|
|
|
|
tag = "latest";
|
|
|
|
|
|
|
|
copyToRoot = pkgs.buildEnv {
|
|
|
|
name = "image-with-certs-root";
|
|
|
|
paths = [
|
|
|
|
pkgs.coreutils
|
|
|
|
pkgs.dockerTools.caCertificates
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2024-06-30 08:16:52 +00:00
|
|
|
config = { };
|
2024-05-02 00:46:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-basic = streamNixShellImage {
|
|
|
|
name = "nix-shell-basic";
|
|
|
|
tag = "latest";
|
|
|
|
drv = pkgs.hello;
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-hook = streamNixShellImage {
|
|
|
|
name = "nix-shell-hook";
|
|
|
|
tag = "latest";
|
|
|
|
drv = pkgs.mkShell {
|
|
|
|
shellHook = ''
|
|
|
|
echo "This is the shell hook!"
|
|
|
|
exit
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-inputs = streamNixShellImage {
|
|
|
|
name = "nix-shell-inputs";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
drv = pkgs.mkShell { nativeBuildInputs = [ pkgs.hello ]; };
|
2024-05-02 00:46:19 +00:00
|
|
|
command = ''
|
|
|
|
hello
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-pass-as-file = streamNixShellImage {
|
|
|
|
name = "nix-shell-pass-as-file";
|
|
|
|
tag = "latest";
|
|
|
|
drv = pkgs.mkShell {
|
|
|
|
str = "this is a string";
|
|
|
|
passAsFile = [ "str" ];
|
|
|
|
};
|
|
|
|
command = ''
|
|
|
|
cat "$strPath"
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-run = streamNixShellImage {
|
|
|
|
name = "nix-shell-run";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
drv = pkgs.mkShell { };
|
2024-05-02 00:46:19 +00:00
|
|
|
run = ''
|
|
|
|
case "$-" in
|
|
|
|
*i*) echo This shell is interactive ;;
|
|
|
|
*) echo This shell is not interactive ;;
|
|
|
|
esac
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-command = streamNixShellImage {
|
|
|
|
name = "nix-shell-command";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
drv = pkgs.mkShell { };
|
2024-05-02 00:46:19 +00:00
|
|
|
command = ''
|
|
|
|
case "$-" in
|
|
|
|
*i*) echo This shell is interactive ;;
|
|
|
|
*) echo This shell is not interactive ;;
|
|
|
|
esac
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-writable-home = streamNixShellImage {
|
|
|
|
name = "nix-shell-writable-home";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
drv = pkgs.mkShell { };
|
2024-05-02 00:46:19 +00:00
|
|
|
run = ''
|
|
|
|
if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then
|
|
|
|
echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! touch $HOME/test-file; then
|
|
|
|
echo "home directory is not writable"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
echo "home directory is writable"
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-nonexistent-home = streamNixShellImage {
|
|
|
|
name = "nix-shell-nonexistent-home";
|
|
|
|
tag = "latest";
|
2024-06-30 08:16:52 +00:00
|
|
|
drv = pkgs.mkShell { };
|
2024-05-02 00:46:19 +00:00
|
|
|
homeDirectory = "/homeless-shelter";
|
|
|
|
run = ''
|
|
|
|
if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then
|
|
|
|
echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if -e $HOME; then
|
|
|
|
echo "home directory exists"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
echo "home directory doesn't exist"
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
nix-shell-build-derivation = streamNixShellImage {
|
|
|
|
name = "nix-shell-build-derivation";
|
|
|
|
tag = "latest";
|
|
|
|
drv = pkgs.hello;
|
|
|
|
run = ''
|
|
|
|
buildDerivation
|
|
|
|
$out/bin/hello
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|