diff --git a/doc/builders/images/dockertools.section.md b/doc/builders/images/dockertools.section.md index 6203b3786bfa..dfc012b80c5a 100644 --- a/doc/builders/images/dockertools.section.md +++ b/doc/builders/images/dockertools.section.md @@ -62,6 +62,8 @@ The above example will build a Docker image `redis/latest` from the given base i - `config` is used to specify the configuration of the containers that will be started off the built image in Docker. The available options are listed in the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions). +- `architecture` is _optional_ and used to specify the image architecture, this is useful for multi-architecture builds that don't need cross compiling. If not specified it will default to `hostPlatform`. + - `diskSize` is used to specify the disk size of the VM used to build the image in megabytes. By default it's 1024 MiB. - `buildVMMemorySize` is used to specify the memory size of the VM to build the image in megabytes. By default it's 512 MiB. @@ -141,6 +143,8 @@ Create a Docker image with many of the store paths being on their own layer to i `config` _optional_ +`architecture` is _optional_ and used to specify the image architecture, this is useful for multi-architecture builds that don't need cross compiling. If not specified it will default to `hostPlatform`. + : Run-time configuration of the container. A full list of the options are available at in the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions). *Default:* `{}` diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix index e76a46131929..98704ecb2fb6 100644 --- a/nixos/tests/docker-tools.nix +++ b/nixos/tests/docker-tools.nix @@ -419,6 +419,20 @@ import ./make-test-python.nix ({ pkgs, ... }: { "docker rmi layered-image-with-path", ) + with subtest("Ensure correct architecture is present in manifests."): + docker.succeed(""" + docker load --input='${examples.build-image-with-architecture}' + docker inspect build-image-with-architecture \ + | ${pkgs.jq}/bin/jq -er '.[] | select(.Architecture=="arm64").Architecture' + docker rmi build-image-with-architecture + """) + docker.succeed(""" + ${examples.layered-image-with-architecture} | docker load + docker inspect layered-image-with-architecture \ + | ${pkgs.jq}/bin/jq -er '.[] | select(.Architecture=="arm64").Architecture' + docker rmi layered-image-with-architecture + """) + with subtest("etc"): docker.succeed("${examples.etc} | docker load") docker.succeed("docker run --rm etc | grep localhost") diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index c6ab4589aefa..48c780e2dbe4 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -74,7 +74,7 @@ let # Reference: https://github.com/opencontainers/image-spec/blob/master/config.md#properties # For the mapping from Nixpkgs system parameters to GOARCH, we can reuse the # mapping from the go package. - defaultArch = go.GOARCH; + defaultArchitecture = go.GOARCH; in rec { @@ -101,8 +101,8 @@ rec { , imageDigest , sha256 , os ? "linux" - , arch ? defaultArch - + , # Image architecture, defaults to the architecture of the `hostPlatform` when unset + arch ? defaultArchitecture # This is used to set name to the pulled image , finalImageName ? imageName # This used to set a tag to the pulled image @@ -514,6 +514,8 @@ rec { keepContentsDirlinks ? false , # Docker config; e.g. what command to run on the container. config ? null + , # Image architecture, defaults to the architecture of the `hostPlatform` when unset + architecture ? defaultArchitecture , # Optional bash script to run on the files prior to fixturizing the layer. extraCommands ? "" , uid ? 0 @@ -546,8 +548,7 @@ rec { baseJson = let pure = writeText "${baseName}-config.json" (builtins.toJSON { - inherit created config; - architecture = defaultArch; + inherit created config architecture; preferLocalBuild = true; os = "linux"; }); @@ -838,6 +839,8 @@ rec { contents ? [ ] , # Docker config; e.g. what command to run on the container. config ? { } + , # Image architecture, defaults to the architecture of the `hostPlatform` when unset + architecture ? defaultArchitecture , # Time of creation of the image. Passing "now" will make the # created date be the time of building. created ? "1970-01-01T00:00:01Z" @@ -869,8 +872,7 @@ rec { streamScript = writePython3 "stream" { } ./stream_layered_image.py; baseJson = writeText "${baseName}-base.json" (builtins.toJSON { - inherit config; - architecture = defaultArch; + inherit config architecture; os = "linux"; }); diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix index 71c3574963c8..5784e650dc2e 100644 --- a/pkgs/build-support/docker/examples.nix +++ b/pkgs/build-support/docker/examples.nix @@ -92,7 +92,7 @@ rec { ]; extraCommands = '' - mkdir -p tmp + mkdir -p tmp/nginx_client_body # nginx still tries to read this directory even if error_log # directive is specifying another file :/ @@ -700,6 +700,21 @@ rec { contents = [ pkgs.bashInteractive ./test-dummy ]; }; + 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. + copyToRoot = [ pkgs.bashInteractive ./test-dummy ]; + }; + + layered-image-with-architecture = pkgs.dockerTools.streamLayeredImage { + name = "layered-image-with-architecture"; + tag = "latest"; + architecture = "arm64"; + contents = [ pkgs.bashInteractive ./test-dummy ]; + }; + # ensure that caCertificates builds image-with-certs = buildImage { name = "image-with-certs";