1# pkgs.dockerTools {#sec-pkgs-dockerTools}
2
3`pkgs.dockerTools` is a set of functions for creating and manipulating Docker images according to the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#docker-image-specification-v120). Docker itself is not used to perform any of the operations done by these functions.
4
5## buildImage {#ssec-pkgs-dockerTools-buildImage}
6
7This function is analogous to the `docker build` command, in that it can be used to build a Docker-compatible repository tarball containing a single image with one or multiple layers. As such, the result is suitable for being loaded in Docker with `docker load`.
8
9The parameters of `buildImage` with relative example values are described below:
10
11[]{#ex-dockerTools-buildImage}
12[]{#ex-dockerTools-buildImage-runAsRoot}
13
14```nix
15buildImage {
16 name = "redis";
17 tag = "latest";
18
19 fromImage = someBaseImage;
20 fromImageName = null;
21 fromImageTag = "latest";
22
23 copyToRoot = pkgs.buildEnv {
24 name = "image-root";
25 paths = [ pkgs.redis ];
26 pathsToLink = [ "/bin" ];
27 };
28
29 runAsRoot = ''
30 #!${pkgs.runtimeShell}
31 mkdir -p /data
32 '';
33
34 config = {
35 Cmd = [ "/bin/redis-server" ];
36 WorkingDir = "/data";
37 Volumes = { "/data" = { }; };
38 };
39
40 diskSize = 1024;
41 buildVMMemorySize = 512;
42}
43```
44
45The above example will build a Docker image `redis/latest` from the given base image. Loading and running this image in Docker results in `redis-server` being started automatically.
46
47- `name` specifies the name of the resulting image. This is the only required argument for `buildImage`.
48
49- `tag` specifies the tag of the resulting image. By default it's `null`, which indicates that the nix output hash will be used as tag.
50
51- `fromImage` is the repository tarball containing the base image. It must be a valid Docker image, such as exported by `docker save`. By default it's `null`, which can be seen as equivalent to `FROM scratch` of a `Dockerfile`.
52
53- `fromImageName` can be used to further specify the base image within the repository, in case it contains multiple images. By default it's `null`, in which case `buildImage` will peek the first image available in the repository.
54
55- `fromImageTag` can be used to further specify the tag of the base image within the repository, in case an image contains multiple tags. By default it's `null`, in which case `buildImage` will peek the first tag available for the base image.
56
57- `copyToRoot` is a derivation that will be copied in the new layer of the resulting image. This can be similarly seen as `ADD contents/ /` in a `Dockerfile`. By default it's `null`.
58
59- `runAsRoot` is a bash script that will run as root in an environment that overlays the existing layers of the base image with the new resulting layer, including the previously copied `contents` derivation. This can be similarly seen as `RUN ...` in a `Dockerfile`.
60
61> **_NOTE:_** Using this parameter requires the `kvm` device to be available.
62
63- `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).
64
65- `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`.
66
67- `diskSize` is used to specify the disk size of the VM used to build the image in megabytes. By default it's 1024 MiB.
68
69- `buildVMMemorySize` is used to specify the memory size of the VM to build the image in megabytes. By default it's 512 MiB.
70
71After the new layer has been created, its closure (to which `contents`, `config` and `runAsRoot` contribute) will be copied in the layer itself. Only new dependencies that are not already in the existing layers will be copied.
72
73At the end of the process, only one new single layer will be produced and added to the resulting image.
74
75The resulting repository will only list the single image `image/tag`. In the case of [the `buildImage` example](#ex-dockerTools-buildImage), it would be `redis/latest`.
76
77It is possible to inspect the arguments with which an image was built using its `buildArgs` attribute.
78
79> **_NOTE:_** If you see errors similar to `getProtocolByName: does not exist (no such protocol name: tcp)` you may need to add `pkgs.iana-etc` to `contents`.
80
81> **_NOTE:_** If you see errors similar to `Error_Protocol ("certificate has unknown CA",True,UnknownCa)` you may need to add `pkgs.cacert` to `contents`.
82
83By default `buildImage` will use a static date of one second past the UNIX Epoch. This allows `buildImage` to produce binary reproducible images. When listing images with `docker images`, the newly created images will be listed like this:
84
85```ShellSession
86$ docker images
87REPOSITORY TAG IMAGE ID CREATED SIZE
88hello latest 08c791c7846e 48 years ago 25.2MB
89```
90
91You can break binary reproducibility but have a sorted, meaningful `CREATED` column by setting `created` to `now`.
92
93```nix
94pkgs.dockerTools.buildImage {
95 name = "hello";
96 tag = "latest";
97 created = "now";
98 copyToRoot = pkgs.buildEnv {
99 name = "image-root";
100 paths = [ pkgs.hello ];
101 pathsToLink = [ "/bin" ];
102 };
103
104 config.Cmd = [ "/bin/hello" ];
105}
106```
107
108Now the Docker CLI will display a reasonable date and sort the images as expected:
109
110```ShellSession
111$ docker images
112REPOSITORY TAG IMAGE ID CREATED SIZE
113hello latest de2bf4786de6 About a minute ago 25.2MB
114```
115
116However, the produced images will not be binary reproducible.
117
118## buildLayeredImage {#ssec-pkgs-dockerTools-buildLayeredImage}
119
120Create a Docker image with many of the store paths being on their own layer to improve sharing between images. The image is realized into the Nix store as a gzipped tarball. Depending on the intended usage, many users might prefer to use `streamLayeredImage` instead, which this function uses internally.
121
122`name`
123
124: The name of the resulting image.
125
126`tag` _optional_
127
128: Tag of the generated image.
129
130 *Default:* the output path's hash
131
132`fromImage` _optional_
133
134: The repository tarball containing the base image. It must be a valid Docker image, such as one exported by `docker save`.
135
136 *Default:* `null`, which can be seen as equivalent to `FROM scratch` of a `Dockerfile`.
137
138`contents` _optional_
139
140: Top-level paths in the container. Either a single derivation, or a list of derivations.
141
142 *Default:* `[]`
143
144`config` _optional_
145
146`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`.
147
148: Run-time configuration of the container. A full list of the options available is in the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions).
149
150 *Default:* `{}`
151
152`created` _optional_
153
154: Date and time the layers were created. Follows the same `now` exception supported by `buildImage`.
155
156 *Default:* `1970-01-01T00:00:01Z`
157
158`maxLayers` _optional_
159
160: Maximum number of layers to create.
161
162 *Default:* `100`
163
164 *Maximum:* `125`
165
166`extraCommands` _optional_
167
168: Shell commands to run while building the final layer, without access to most of the layer contents. Changes to this layer are "on top" of all the other layers, so can create additional directories and files.
169
170`fakeRootCommands` _optional_
171
172: Shell commands to run while creating the archive for the final layer in a fakeroot environment. Unlike `extraCommands`, you can run `chown` to change the owners of the files in the archive, changing fakeroot's state instead of the real filesystem. The latter would require privileges that the build user does not have. Static binaries do not interact with the fakeroot environment. By default all files in the archive will be owned by root.
173
174`enableFakechroot` _optional_
175
176: Whether to run in `fakeRootCommands` in `fakechroot`, making programs behave as though `/` is the root of the image being created, while files in the Nix store are available as usual. This allows scripts that perform installation in `/` to work as expected. Considering that `fakechroot` is implemented via the same mechanism as `fakeroot`, the same caveats apply.
177
178 *Default:* `false`
179
180### Behavior of `contents` in the final image {#dockerTools-buildLayeredImage-arg-contents}
181
182Each path directly listed in `contents` will have a symlink in the root of the image.
183
184For example:
185
186```nix
187pkgs.dockerTools.buildLayeredImage {
188 name = "hello";
189 contents = [ pkgs.hello ];
190}
191```
192
193will create symlinks for all the paths in the `hello` package:
194
195```ShellSession
196/bin/hello -> /nix/store/h1zb1padqbbb7jicsvkmrym3r6snphxg-hello-2.10/bin/hello
197/share/info/hello.info -> /nix/store/h1zb1padqbbb7jicsvkmrym3r6snphxg-hello-2.10/share/info/hello.info
198/share/locale/bg/LC_MESSAGES/hello.mo -> /nix/store/h1zb1padqbbb7jicsvkmrym3r6snphxg-hello-2.10/share/locale/bg/LC_MESSAGES/hello.mo
199```
200
201### Automatic inclusion of `config` references {#dockerTools-buildLayeredImage-arg-config}
202
203The closure of `config` is automatically included in the closure of the final image.
204
205This allows you to make very simple Docker images with very little code. This container will start up and run `hello`:
206
207```nix
208pkgs.dockerTools.buildLayeredImage {
209 name = "hello";
210 config.Cmd = [ "${pkgs.hello}/bin/hello" ];
211}
212```
213
214### Adjusting `maxLayers` {#dockerTools-buildLayeredImage-arg-maxLayers}
215
216Increasing the `maxLayers` increases the number of layers which have a chance to be shared between different images.
217
218Modern Docker installations support up to 128 layers, but older versions support as few as 42.
219
220If the produced image will not be extended by other Docker builds, it is safe to set `maxLayers` to `128`. However, it will be impossible to extend the image further.
221
222The first (`maxLayers-2`) most "popular" paths will have their own individual layers, then layer \#`maxLayers-1` will contain all the remaining "unpopular" paths, and finally layer \#`maxLayers` will contain the Image configuration.
223
224Docker's Layers are not inherently ordered, they are content-addressable and are not explicitly layered until they are composed in to an Image.
225
226## streamLayeredImage {#ssec-pkgs-dockerTools-streamLayeredImage}
227
228Builds a script which, when run, will stream an uncompressed tarball of a Docker image to stdout. The arguments to this function are as for `buildLayeredImage`. This method of constructing an image does not realize the image into the Nix store, so it saves on IO and disk/cache space, particularly with large images.
229
230The image produced by running the output script can be piped directly into `docker load`, to load it into the local docker daemon:
231
232```ShellSession
233$(nix-build) | docker load
234```
235
236Alternatively, the image be piped via `gzip` into `skopeo`, e.g., to copy it into a registry:
237
238```ShellSession
239$(nix-build) | gzip --fast | skopeo copy docker-archive:/dev/stdin docker://some_docker_registry/myimage:tag
240```
241
242## pullImage {#ssec-pkgs-dockerTools-fetchFromRegistry}
243
244This function is analogous to the `docker pull` command, in that it can be used to pull a Docker image from a Docker registry. By default [Docker Hub](https://hub.docker.com/) is used to pull images.
245
246Its parameters are described in the example below:
247
248```nix
249pullImage {
250 imageName = "nixos/nix";
251 imageDigest =
252 "sha256:473a2b527958665554806aea24d0131bacec46d23af09fef4598eeab331850fa";
253 finalImageName = "nix";
254 finalImageTag = "2.11.1";
255 sha256 = "sha256-qvhj+Hlmviz+KEBVmsyPIzTB3QlVAFzwAY1zDPIBGxc=";
256 os = "linux";
257 arch = "x86_64";
258}
259```
260
261- `imageName` specifies the name of the image to be downloaded, which can also include the registry namespace (e.g. `nixos`). This argument is required.
262
263- `imageDigest` specifies the digest of the image to be downloaded. This argument is required.
264
265- `finalImageName`, if specified, this is the name of the image to be created. Note it is never used to fetch the image since we prefer to rely on the immutable digest ID. By default it's equal to `imageName`.
266
267- `finalImageTag`, if specified, this is the tag of the image to be created. Note it is never used to fetch the image since we prefer to rely on the immutable digest ID. By default it's `latest`.
268
269- `sha256` is the checksum of the whole fetched image. This argument is required.
270
271- `os`, if specified, is the operating system of the fetched image. By default it's `linux`.
272
273- `arch`, if specified, is the cpu architecture of the fetched image. By default it's `x86_64`.
274
275`nix-prefetch-docker` command can be used to get required image parameters:
276
277```ShellSession
278$ nix run nixpkgs#nix-prefetch-docker -- --image-name mysql --image-tag 5
279```
280
281Since a given `imageName` may transparently refer to a manifest list of images which support multiple architectures and/or operating systems, you can supply the `--os` and `--arch` arguments to specify exactly which image you want. By default it will match the OS and architecture of the host the command is run on.
282
283```ShellSession
284$ nix-prefetch-docker --image-name mysql --image-tag 5 --arch x86_64 --os linux
285```
286
287Desired image name and tag can be set using `--final-image-name` and `--final-image-tag` arguments:
288
289```ShellSession
290$ nix-prefetch-docker --image-name mysql --image-tag 5 --final-image-name eu.gcr.io/my-project/mysql --final-image-tag prod
291```
292
293## exportImage {#ssec-pkgs-dockerTools-exportImage}
294
295This function is analogous to the `docker export` command, in that it can be used to flatten a Docker image that contains multiple layers. It is in fact the result of the merge of all the layers of the image. As such, the result is suitable for being imported in Docker with `docker import`.
296
297> **_NOTE:_** Using this function requires the `kvm` device to be available.
298
299The parameters of `exportImage` are the following:
300
301```nix
302exportImage {
303 fromImage = someLayeredImage;
304 fromImageName = null;
305 fromImageTag = null;
306
307 name = someLayeredImage.name;
308}
309```
310
311The parameters relative to the base image have the same synopsis as described in [buildImage](#ssec-pkgs-dockerTools-buildImage), except that `fromImage` is the only required argument in this case.
312
313The `name` argument is the name of the derivation output, which defaults to `fromImage.name`.
314
315## Environment Helpers {#ssec-pkgs-dockerTools-helpers}
316
317Some packages expect certain files to be available globally.
318When building an image from scratch (i.e. without `fromImage`), these files are missing.
319`pkgs.dockerTools` provides some helpers to set up an environment with the necessary files.
320You can include them in `copyToRoot` like this:
321
322```nix
323buildImage {
324 name = "environment-example";
325 copyToRoot = with pkgs.dockerTools; [
326 usrBinEnv
327 binSh
328 caCertificates
329 fakeNss
330 ];
331}
332```
333
334### usrBinEnv {#sssec-pkgs-dockerTools-helpers-usrBinEnv}
335
336This provides the `env` utility at `/usr/bin/env`.
337
338### binSh {#sssec-pkgs-dockerTools-helpers-binSh}
339
340This provides `bashInteractive` at `/bin/sh`.
341
342### caCertificates {#sssec-pkgs-dockerTools-helpers-caCertificates}
343
344This sets up `/etc/ssl/certs/ca-certificates.crt`.
345
346### fakeNss {#sssec-pkgs-dockerTools-helpers-fakeNss}
347
348Provides `/etc/passwd` and `/etc/group` that contain root and nobody.
349Useful when packaging binaries that insist on using nss to look up
350username/groups (like nginx).
351
352### shadowSetup {#ssec-pkgs-dockerTools-shadowSetup}
353
354This constant string is a helper for setting up the base files for managing users and groups, only if such files don't exist already. It is suitable for being used in a [`buildImage` `runAsRoot`](#ex-dockerTools-buildImage-runAsRoot) script for cases like in the example below:
355
356```nix
357buildImage {
358 name = "shadow-basic";
359
360 runAsRoot = ''
361 #!${pkgs.runtimeShell}
362 ${pkgs.dockerTools.shadowSetup}
363 groupadd -r redis
364 useradd -r -g redis redis
365 mkdir /data
366 chown redis:redis /data
367 '';
368}
369```
370
371Creating base files like `/etc/passwd` or `/etc/login.defs` is necessary for shadow-utils to manipulate users and groups.
372
373## fakeNss {#ssec-pkgs-dockerTools-fakeNss}
374
375If your primary goal is providing a basic skeleton for user lookups to work,
376and/or a lesser privileged user, adding `pkgs.fakeNss` to
377the container image root might be the better choice than a custom script
378running `useradd` and friends.
379
380It provides a `/etc/passwd` and `/etc/group`, containing `root` and `nobody`
381users and groups.
382
383It also provides a `/etc/nsswitch.conf`, configuring NSS host resolution to
384first check `/etc/hosts`, before checking DNS, as the default in the absence of
385a config file (`dns [!UNAVAIL=return] files`) is quite unexpected.
386
387You can pair it with `binSh`, which provides `bin/sh` as a symlink
388to `bashInteractive` (as `/bin/sh` is configured as a shell).
389
390```nix
391buildImage {
392 name = "shadow-basic";
393
394 copyToRoot = pkgs.buildEnv {
395 name = "image-root";
396 paths = [ binSh pkgs.fakeNss ];
397 pathsToLink = [ "/bin" "/etc" "/var" ];
398 };
399}
400```
401
402## buildNixShellImage {#ssec-pkgs-dockerTools-buildNixShellImage}
403
404Create a Docker image that sets up an environment similar to that of running `nix-shell` on a derivation.
405When run in Docker, this environment somewhat resembles the Nix sandbox typically used by `nix-build`, with a major difference being that access to the internet is allowed.
406It additionally also behaves like an interactive `nix-shell`, running things like `shellHook` and setting an interactive prompt.
407If the derivation is fully buildable (i.e. `nix-build` can be used on it), running `buildDerivation` inside such a Docker image will build the derivation, with all its outputs being available in the correct `/nix/store` paths, pointed to by the respective environment variables like `$out`, etc.
408
409::: {.warning}
410The behavior doesn't match `nix-shell` or `nix-build` exactly and this function is known not to work correctly for e.g. fixed-output derivations, content-addressed derivations, impure derivations and other special types of derivations.
411:::
412
413### Arguments {#ssec-pkgs-dockerTools-buildNixShellImage-arguments}
414
415`drv`
416
417: The derivation on which to base the Docker image.
418
419 Adding packages to the Docker image is possible by e.g. extending the list of `nativeBuildInputs` of this derivation like
420
421 ```nix
422 buildNixShellImage {
423 drv = someDrv.overrideAttrs (old: {
424 nativeBuildInputs = old.nativeBuildInputs or [] ++ [
425 somethingExtra
426 ];
427 });
428 # ...
429 }
430 ```
431
432 Similarly, you can extend the image initialization script by extending `shellHook`
433
434`name` _optional_
435
436: The name of the resulting image.
437
438 *Default:* `drv.name + "-env"`
439
440`tag` _optional_
441
442: Tag of the generated image.
443
444 *Default:* the resulting image derivation output path's hash
445
446`uid`/`gid` _optional_
447
448: The user/group ID to run the container as. This is like a `nixbld` build user.
449
450 *Default:* 1000/1000
451
452`homeDirectory` _optional_
453
454: The home directory of the user the container is running as
455
456 *Default:* `/build`
457
458`shell` _optional_
459
460: The path to the `bash` binary to use as the shell. This shell is started when running the image.
461
462 *Default:* `pkgs.bashInteractive + "/bin/bash"`
463
464`command` _optional_
465
466: Run this command in the environment of the derivation, in an interactive shell. See the `--command` option in the [`nix-shell` documentation](https://nixos.org/manual/nix/stable/command-ref/nix-shell.html?highlight=nix-shell#options).
467
468 *Default:* (none)
469
470`run` _optional_
471
472: Same as `command`, but runs the command in a non-interactive shell instead. See the `--run` option in the [`nix-shell` documentation](https://nixos.org/manual/nix/stable/command-ref/nix-shell.html?highlight=nix-shell#options).
473
474 *Default:* (none)
475
476### Example {#ssec-pkgs-dockerTools-buildNixShellImage-example}
477
478The following shows how to build the `pkgs.hello` package inside a Docker container built with `buildNixShellImage`.
479
480```nix
481with import <nixpkgs> {};
482dockerTools.buildNixShellImage {
483 drv = hello;
484}
485```
486
487Build the derivation:
488
489```console
490nix-build hello.nix
491```
492
493 these 8 derivations will be built:
494 /nix/store/xmw3a5ln29rdalavcxk1w3m4zb2n7kk6-nix-shell-rc.drv
495 ...
496 Creating layer 56 from paths: ['/nix/store/crpnj8ssz0va2q0p5ibv9i6k6n52gcya-stdenv-linux']
497 Creating layer 57 with customisation...
498 Adding manifests...
499 Done.
500 /nix/store/cpyn1lc897ghx0rhr2xy49jvyn52bazv-hello-2.12-env.tar.gz
501
502Load the image:
503
504```console
505docker load -i result
506```
507
508 0d9f4c4cd109: Loading layer [==================================================>] 2.56MB/2.56MB
509 ...
510 ab1d897c0697: Loading layer [==================================================>] 10.24kB/10.24kB
511 Loaded image: hello-2.12-env:pgj9h98nal555415faa43vsydg161bdz
512
513Run the container:
514
515```console
516docker run -it hello-2.12-env:pgj9h98nal555415faa43vsydg161bdz
517```
518
519 [nix-shell:/build]$
520
521In the running container, run the build:
522
523```console
524buildDerivation
525```
526
527 unpacking sources
528 unpacking source archive /nix/store/8nqv6kshb3vs5q5bs2k600xpj5bkavkc-hello-2.12.tar.gz
529 ...
530 patching script interpreter paths in /nix/store/z5wwy5nagzy15gag42vv61c2agdpz2f2-hello-2.12
531 checking for references to /build/ in /nix/store/z5wwy5nagzy15gag42vv61c2agdpz2f2-hello-2.12...
532
533Check the build result:
534
535```console
536$out/bin/hello
537```
538
539 Hello, world!