Docker - Building container images with Nix
Example flake showing buildLayeredImage and buildImage with Ubuntu base.
Try it out
cd wiki/docker && nix develop -c $SHELL
or with nix-output-monitor
(nom develop -c $SHELL) for a nice overview of the build progress
This will build and load two Docker images:
nix-shell:latest- Pure Nix image using buildLayeredImageubuntu-nix:latest- Ubuntu base with Nix tools using buildImage
flake.nix
{
description = "Nix Docker image examples";
inputs = {
nixpkgs.url = "https://flakehub.com/f/JHOFER-Cloud/NixOS-nixpkgs/0.1.tar.gz"; # usually github:NixOS/nixpkgs/nixpkgs-unstable
flake-utils.url = "github:numtide/flake-utils";
};
outputs = {
nixpkgs,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system};
# Get Linux packages - works on macOS with Determinate's built-in linux-builder
# This uses the linux-builder to build natively for Linux (fast, fully cached)
linuxPkgs = import pkgs.path {system = "x86_64-linux";};
# Alternative: Cross-compile to Linux (no cache, slower first build)
# linuxPkgs = pkgs.pkgsCross.musl64;
# Example 1: buildLayeredImage - pure Nix, from scratch
layeredImage = pkgs.dockerTools.buildLayeredImage {
name = "nix-shell";
tag = "latest";
contents = [linuxPkgs.busybox];
config.Cmd = ["/bin/sh"];
};
# Example 2: buildImage with Ubuntu base
ubuntuBase = pkgs.dockerTools.pullImage {
imageName = "ubuntu";
imageDigest = "sha256:cd1dba651b3080c3686ecf4e3c4220f026b521fb76978881737d24f200828b2b";
sha256 = "sha256-9vmJV6M21tZPk39lCCdCrwHR55gNzO1ka2De51IR9qs=";
finalImageTag = "24.04";
};
ubuntuImage = pkgs.dockerTools.buildImage {
name = "ubuntu-nix";
tag = "latest";
fromImage = ubuntuBase;
copyToRoot = pkgs.buildEnv {
name = "nix-tools";
paths = [linuxPkgs.busybox];
};
config.Cmd = ["/bin/sh"];
};
in {
devShells.default = pkgs.mkShell {
shellHook = ''
echo "Loading Docker images..."
if command -v podman &>/dev/null; then
podman load < ${layeredImage}
podman load < ${ubuntuImage}
elif command -v docker &>/dev/null; then
docker load < ${layeredImage}
docker load < ${ubuntuImage}
else
echo "No container runtime found"
exit 1
fi
echo "Images loaded: ${layeredImage.imageName}:${layeredImage.imageTag}, ${ubuntuImage.imageName}:${ubuntuImage.imageTag}"
'';
};
});
}
How it works
Linux Builder (Recommended)
The flake uses Determinate’s built-in Linux builder on macOS:
linuxPkgs = import pkgs.path {system = "x86_64-linux";};
This builds natively for Linux using the remote builder, which is fast and fully cached.
Cross-compilation Alternative
Alternatively, you can cross-compile using:
linuxPkgs = pkgs.pkgsCross.musl64;
Note: This approach has no binary cache, so first builds will be slower.