1# Examples of using the docker tools to build packages.
2#
3# This file defines several docker images. In order to use an image,
4# build its derivation with `nix-build`, and then load the result with
5# `docker load`. For example:
6#
7# $ nix-build '<nixpkgs>' -A dockerTools.examples.redis
8# $ docker load < result
9
10{
11 pkgs,
12 buildImage,
13 buildLayeredImage,
14 fakeNss,
15 pullImage,
16 shadowSetup,
17 buildImageWithNixDb,
18 pkgsCross,
19 streamNixShellImage,
20}:
21
22let
23 nixosLib = import ../../../nixos/lib {
24 # Experimental features need testing too, but there's no point in warning
25 # about it, so we enable the feature flag.
26 featureFlags.minimalModules = { };
27 };
28 evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; };
29
30 nginxArguments =
31 let
32 nginxPort = "80";
33 nginxConf = pkgs.writeText "nginx.conf" ''
34 user nobody nobody;
35 daemon off;
36 error_log /dev/stdout info;
37 pid /dev/null;
38 events {}
39 http {
40 access_log /dev/stdout;
41 server {
42 listen ${nginxPort};
43 index index.html;
44 location / {
45 root ${nginxWebRoot};
46 }
47 }
48 }
49 '';
50 nginxWebRoot = pkgs.writeTextDir "index.html" ''
51 <html><body><h1>Hello from NGINX</h1></body></html>
52 '';
53 in
54 {
55 name = "nginx-container";
56 tag = "latest";
57 contents = [
58 fakeNss
59 pkgs.nginx
60 ];
61
62 extraCommands = ''
63 mkdir -p tmp/nginx_client_body
64
65 # nginx still tries to read this directory even if error_log
66 # directive is specifying another file :/
67 mkdir -p var/log/nginx
68 '';
69
70 config = {
71 Cmd = [
72 "nginx"
73 "-c"
74 nginxConf
75 ];
76 ExposedPorts = {
77 "${nginxPort}/tcp" = { };
78 };
79 };
80 };
81
82in
83
84rec {
85 # 1. basic example
86 bash = buildImage {
87 name = "bash";
88 tag = "latest";
89 copyToRoot = pkgs.buildEnv {
90 name = "image-root";
91 paths = [ pkgs.bashInteractive ];
92 pathsToLink = [ "/bin" ];
93 };
94 };
95
96 # 2. service example, layered on another image
97 redis = buildImage {
98 name = "redis";
99 tag = "latest";
100
101 # for example's sake, we can layer redis on top of bash or debian
102 fromImage = bash;
103 # fromImage = debian;
104
105 copyToRoot = pkgs.buildEnv {
106 name = "image-root";
107 paths = [ pkgs.redis ];
108 pathsToLink = [ "/bin" ];
109 };
110
111 runAsRoot = ''
112 mkdir -p /data
113 cat >/bin/healthcheck <<-'EOF'
114 set -x
115 probe="$(/bin/redis-cli ping)"
116 echo "$probe"
117 if [ "$probe" = 'PONG' ]; then
118 exit 0
119 fi
120 exit 1
121 EOF
122 chmod +x /bin/healthcheck
123 '';
124
125 config = {
126 Cmd = [ "/bin/redis-server" ];
127 WorkingDir = "/data";
128 Volumes = {
129 "/data" = { };
130 };
131 Healthcheck = {
132 Test = [
133 "CMD-SHELL"
134 "/bin/healthcheck"
135 ];
136 Interval = 30000000000;
137 Timeout = 10000000000;
138 Retries = 3;
139 };
140 };
141 };
142
143 # 3. another service example
144 nginx = buildLayeredImage nginxArguments;
145
146 # Used to demonstrate how virtualisation.oci-containers.imageStream works
147 nginxStream = pkgs.dockerTools.streamLayeredImage nginxArguments;
148
149 # 4. example of pulling an image. could be used as a base for other images
150 nixFromDockerHub = pullImage {
151 imageName = "nixos/nix";
152 imageDigest = "sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357";
153 hash = "sha256-xxZ4UW6jRIVAzlVYA62awcopzcYNViDyh6q1yocF3KU=";
154 finalImageTag = "2.2.1";
155 finalImageName = "nix";
156 };
157 # Same example, but re-fetches every time the fetcher implementation changes.
158 # NOTE: Only use this for testing, or you'd be wasting a lot of time, network and space.
159 testNixFromDockerHub = pkgs.testers.invalidateFetcherByDrvHash pullImage {
160 imageName = "nixos/nix";
161 imageDigest = "sha256:85299d86263a3059cf19f419f9d286cc9f06d3c13146a8ebbb21b3437f598357";
162 hash = "sha256-xxZ4UW6jRIVAzlVYA62awcopzcYNViDyh6q1yocF3KU=";
163 finalImageTag = "2.2.1";
164 finalImageName = "nix";
165 };
166
167 # 5. example of multiple contents, emacs and vi happily coexisting
168 editors = buildImage {
169 name = "editors";
170 copyToRoot = pkgs.buildEnv {
171 name = "image-root";
172 pathsToLink = [ "/bin" ];
173 paths = [
174 pkgs.coreutils
175 pkgs.bash
176 pkgs.emacs
177 pkgs.vim
178 pkgs.nano
179 ];
180 };
181 };
182
183 # 6. nix example to play with the container nix store
184 # docker run -it --rm nix nix-store -qR $(nix-build '<nixpkgs>' -A nix)
185 nix = buildImageWithNixDb {
186 name = "nix";
187 tag = "latest";
188 copyToRoot = pkgs.buildEnv {
189 name = "image-root";
190 pathsToLink = [ "/bin" ];
191 paths = [
192 # nix-store uses cat program to display results as specified by
193 # the image env variable NIX_PAGER.
194 pkgs.coreutils
195 pkgs.nix
196 pkgs.bash
197 ];
198 };
199 config = {
200 Env = [
201 "NIX_PAGER=cat"
202 # A user is required by nix
203 # https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
204 "USER=nobody"
205 ];
206 };
207 };
208
209 # 7. example of adding something on top of an image pull by our
210 # dockerTools chain.
211 onTopOfPulledImage = buildImage {
212 name = "onTopOfPulledImage";
213 tag = "latest";
214 fromImage = nixFromDockerHub;
215 copyToRoot = pkgs.buildEnv {
216 name = "image-root";
217 pathsToLink = [ "/bin" ];
218 paths = [ pkgs.hello ];
219 };
220 };
221
222 # 8. regression test for erroneous use of eval and string expansion.
223 # See issue #34779 and PR #40947 for details.
224 runAsRootExtraCommands = pkgs.dockerTools.buildImage {
225 name = "runAsRootExtraCommands";
226 tag = "latest";
227 copyToRoot = pkgs.buildEnv {
228 name = "image-root";
229 pathsToLink = [ "/bin" ];
230 paths = [ pkgs.coreutils ];
231 };
232 # The parens here are to create problematic bash to embed and eval. In case
233 # this is *embedded* into the script (with nix expansion) the initial quotes
234 # will close the string and the following parens are unexpected
235 runAsRoot = ''echo "(runAsRoot)" > runAsRoot'';
236 extraCommands = ''echo "(extraCommand)" > extraCommands'';
237 };
238
239 # 9. Ensure that setting created to now results in a date which
240 # isn't the epoch + 1
241 unstableDate = pkgs.dockerTools.buildImage {
242 name = "unstable-date";
243 tag = "latest";
244 copyToRoot = pkgs.buildEnv {
245 name = "image-root";
246 pathsToLink = [ "/bin" ];
247 paths = [ pkgs.coreutils ];
248 };
249 created = "now";
250 };
251
252 # 10. Create a layered image
253 layered-image = pkgs.dockerTools.buildLayeredImage {
254 name = "layered-image";
255 tag = "latest";
256 extraCommands = ''echo "(extraCommand)" > extraCommands'';
257 config.Cmd = [ "${pkgs.hello}/bin/hello" ];
258 contents = [
259 pkgs.hello
260 pkgs.bash
261 pkgs.coreutils
262 ];
263 };
264
265 # 11. Create an image on top of a layered image
266 layered-on-top = pkgs.dockerTools.buildImage {
267 name = "layered-on-top";
268 tag = "latest";
269 fromImage = layered-image;
270 extraCommands = ''
271 mkdir ./example-output
272 chmod 777 ./example-output
273 '';
274 config = {
275 Env = [ "PATH=${pkgs.coreutils}/bin/" ];
276 WorkingDir = "/example-output";
277 Cmd = [
278 "${pkgs.bash}/bin/bash"
279 "-c"
280 "echo hello > foo; cat foo"
281 ];
282 };
283 };
284
285 # 12 Create a layered image on top of a layered image
286 layered-on-top-layered = pkgs.dockerTools.buildLayeredImage {
287 name = "layered-on-top-layered";
288 tag = "latest";
289 fromImage = layered-image;
290 extraCommands = ''
291 mkdir ./example-output
292 chmod 777 ./example-output
293 '';
294 config = {
295 Env = [ "PATH=${pkgs.coreutils}/bin/" ];
296 WorkingDir = "/example-output";
297 Cmd = [
298 "${pkgs.bash}/bin/bash"
299 "-c"
300 "echo hello > foo; cat foo"
301 ];
302 };
303 };
304
305 # 13. example of running something as root on top of a parent image
306 # Regression test related to PR #52109
307 runAsRootParentImage = buildImage {
308 name = "runAsRootParentImage";
309 tag = "latest";
310 runAsRoot = "touch /example-file";
311 fromImage = bash;
312 };
313
314 # 14. example of 3 layers images This image is used to verify the
315 # order of layers is correct.
316 # It allows to validate
317 # - the layer of parent are below
318 # - the order of parent layer is preserved at image build time
319 # (this is why there are 3 images)
320 layersOrder =
321 let
322 l1 = pkgs.dockerTools.buildImage {
323 name = "l1";
324 tag = "latest";
325 extraCommands = ''
326 mkdir -p tmp
327 echo layer1 > tmp/layer1
328 echo layer1 > tmp/layer2
329 echo layer1 > tmp/layer3
330 '';
331 };
332 l2 = pkgs.dockerTools.buildImage {
333 name = "l2";
334 fromImage = l1;
335 tag = "latest";
336 extraCommands = ''
337 mkdir -p tmp
338 echo layer2 > tmp/layer2
339 echo layer2 > tmp/layer3
340 '';
341 };
342 in
343 pkgs.dockerTools.buildImage {
344 name = "l3";
345 fromImage = l2;
346 tag = "latest";
347 copyToRoot = pkgs.buildEnv {
348 name = "image-root";
349 pathsToLink = [ "/bin" ];
350 paths = [ pkgs.coreutils ];
351 };
352 extraCommands = ''
353 mkdir -p tmp
354 echo layer3 > tmp/layer3
355 '';
356 };
357
358 # 15. Environment variable inheritance.
359 # Child image should inherit parents environment variables,
360 # optionally overriding them.
361 environmentVariablesParent = pkgs.dockerTools.buildImage {
362 name = "parent";
363 tag = "latest";
364 config = {
365 Env = [
366 "FROM_PARENT=true"
367 "LAST_LAYER=parent"
368 ];
369 };
370 };
371
372 environmentVariables = pkgs.dockerTools.buildImage {
373 name = "child";
374 fromImage = environmentVariablesParent;
375 tag = "latest";
376 copyToRoot = pkgs.buildEnv {
377 name = "image-root";
378 pathsToLink = [ "/bin" ];
379 paths = [ pkgs.coreutils ];
380 };
381 config = {
382 Env = [
383 "FROM_CHILD=true"
384 "LAST_LAYER=child"
385 ];
386 };
387 };
388
389 environmentVariablesLayered = pkgs.dockerTools.buildLayeredImage {
390 name = "child";
391 fromImage = environmentVariablesParent;
392 tag = "latest";
393 contents = [ pkgs.coreutils ];
394 config = {
395 Env = [
396 "FROM_CHILD=true"
397 "LAST_LAYER=child"
398 ];
399 };
400 };
401
402 # 16. Create another layered image, for comparing layers with image 10.
403 another-layered-image = pkgs.dockerTools.buildLayeredImage {
404 name = "another-layered-image";
405 tag = "latest";
406 config.Cmd = [ "${pkgs.hello}/bin/hello" ];
407 };
408
409 # 17. Create a layered image with only 2 layers
410 two-layered-image = pkgs.dockerTools.buildLayeredImage {
411 name = "two-layered-image";
412 tag = "latest";
413 config.Cmd = [ "${pkgs.hello}/bin/hello" ];
414 contents = [
415 pkgs.bash
416 pkgs.hello
417 ];
418 maxLayers = 2;
419 };
420
421 # 18. Create a layered image with more packages than max layers.
422 # coreutils and hello are part of the same layer
423 bulk-layer = pkgs.dockerTools.buildLayeredImage {
424 name = "bulk-layer";
425 tag = "latest";
426 contents = with pkgs; [
427 coreutils
428 hello
429 ];
430 maxLayers = 2;
431 };
432
433 # 19. Create a layered image with a base image and more packages than max
434 # layers. coreutils and hello are part of the same layer
435 layered-bulk-layer = pkgs.dockerTools.buildLayeredImage {
436 name = "layered-bulk-layer";
437 tag = "latest";
438 fromImage = two-layered-image;
439 contents = with pkgs; [
440 coreutils
441 hello
442 ];
443 maxLayers = 4;
444 };
445
446 # 20. Create a "layered" image without nix store layers. This is not
447 # recommended, but can be useful for base images in rare cases.
448 no-store-paths = pkgs.dockerTools.buildLayeredImage {
449 name = "no-store-paths";
450 tag = "latest";
451 extraCommands = ''
452 # This removes sharing of busybox and is not recommended. We do this
453 # to make the example suitable as a test case with working binaries.
454 cp -r ${pkgs.pkgsStatic.busybox}/* .
455
456 # This is a "build" dependency that will not appear in the image
457 ${pkgs.hello}/bin/hello
458 '';
459 };
460
461 nixLayered = pkgs.dockerTools.buildLayeredImageWithNixDb {
462 name = "nix-layered";
463 tag = "latest";
464 contents = [
465 # nix-store uses cat program to display results as specified by
466 # the image env variable NIX_PAGER.
467 pkgs.coreutils
468 pkgs.nix
469 pkgs.bash
470 ];
471 config = {
472 Env = [
473 "NIX_PAGER=cat"
474 # A user is required by nix
475 # https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
476 "USER=nobody"
477 ];
478 };
479 };
480
481 # 21. Support files in the store on buildLayeredImage
482 # See: https://github.com/NixOS/nixpkgs/pull/91084#issuecomment-653496223
483 filesInStore = pkgs.dockerTools.buildLayeredImageWithNixDb {
484 name = "file-in-store";
485 tag = "latest";
486 contents = [
487 pkgs.coreutils
488 pkgs.nix
489 (pkgs.writeScriptBin "myscript" ''
490 #!${pkgs.runtimeShell}
491 cat ${pkgs.writeText "somefile" "some data"}
492 '')
493 ];
494 config = {
495 Cmd = [ "myscript" ];
496 # For some reason 'nix-store --verify' requires this environment variable
497 Env = [ "USER=root" ];
498 };
499 };
500
501 # 22. Ensure that setting created to now results in a date which
502 # isn't the epoch + 1 for layered images.
503 unstableDateLayered = pkgs.dockerTools.buildLayeredImage {
504 name = "unstable-date-layered";
505 tag = "latest";
506 contents = [ pkgs.coreutils ];
507 created = "now";
508 };
509
510 # 23. Ensure that layers are unpacked in the correct order before the
511 # runAsRoot script is executed.
512 layersUnpackOrder =
513 let
514 layerOnTopOf =
515 parent: layerName:
516 pkgs.dockerTools.buildImage {
517 name = "layers-unpack-order-${layerName}";
518 tag = "latest";
519 fromImage = parent;
520 copyToRoot = pkgs.buildEnv {
521 name = "image-root";
522 pathsToLink = [ "/bin" ];
523 paths = [ pkgs.coreutils ];
524 };
525 runAsRoot = ''
526 #!${pkgs.runtimeShell}
527 echo -n "${layerName}" >> /layer-order
528 '';
529 };
530 # When executing the runAsRoot script when building layer C, if layer B is
531 # not unpacked on top of layer A, the contents of /layer-order will not be
532 # "ABC".
533 layerA = layerOnTopOf null "a";
534 layerB = layerOnTopOf layerA "b";
535 layerC = layerOnTopOf layerB "c";
536 in
537 layerC;
538
539 bashUncompressed = pkgs.dockerTools.buildImage {
540 name = "bash-uncompressed";
541 tag = "latest";
542 compressor = "none";
543 # Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
544 copyToRoot = pkgs.bashInteractive;
545 };
546
547 bashZstdCompressed = pkgs.dockerTools.buildImage {
548 name = "bash-zstd";
549 tag = "latest";
550 compressor = "zstd";
551 # Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
552 copyToRoot = pkgs.bashInteractive;
553 };
554
555 # buildImage without explicit tag
556 bashNoTag = pkgs.dockerTools.buildImage {
557 name = "bash-no-tag";
558 # Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
559 copyToRoot = pkgs.bashInteractive;
560 };
561
562 # buildLayeredImage without explicit tag
563 bashNoTagLayered = pkgs.dockerTools.buildLayeredImage {
564 name = "bash-no-tag-layered";
565 contents = pkgs.bashInteractive;
566 };
567
568 # buildLayeredImage without compression
569 bashLayeredUncompressed = pkgs.dockerTools.buildLayeredImage {
570 name = "bash-layered-uncompressed";
571 tag = "latest";
572 compressor = "none";
573 contents = pkgs.bashInteractive;
574 };
575
576 # buildLayeredImage with zstd compression
577 bashLayeredZstdCompressed = pkgs.dockerTools.buildLayeredImage {
578 name = "bash-layered-zstd";
579 tag = "latest";
580 compressor = "zstd";
581 contents = pkgs.bashInteractive;
582 };
583
584 # streamLayeredImage without explicit tag
585 bashNoTagStreamLayered = pkgs.dockerTools.streamLayeredImage {
586 name = "bash-no-tag-stream-layered";
587 contents = pkgs.bashInteractive;
588 };
589
590 # buildLayeredImage with non-root user
591 bashLayeredWithUser =
592 let
593 nonRootShadowSetup =
594 {
595 user,
596 uid,
597 gid ? uid,
598 }:
599 with pkgs;
600 [
601 (writeTextDir "etc/shadow" ''
602 root:!x:::::::
603 ${user}:!:::::::
604 '')
605 (writeTextDir "etc/passwd" ''
606 root:x:0:0::/root:${runtimeShell}
607 ${user}:x:${toString uid}:${toString gid}::/home/${user}:
608 '')
609 (writeTextDir "etc/group" ''
610 root:x:0:
611 ${user}:x:${toString gid}:
612 '')
613 (writeTextDir "etc/gshadow" ''
614 root:x::
615 ${user}:x::
616 '')
617 ];
618 in
619 pkgs.dockerTools.buildLayeredImage {
620 name = "bash-layered-with-user";
621 tag = "latest";
622 contents = [
623 pkgs.bash
624 pkgs.coreutils
625 ]
626 ++ nonRootShadowSetup {
627 uid = 999;
628 user = "somebody";
629 };
630 };
631
632 # basic example, with cross compilation
633 cross =
634 let
635 # Cross compile for x86_64 if on aarch64
636 crossPkgs =
637 if pkgs.stdenv.hostPlatform.system == "aarch64-linux" then
638 pkgsCross.gnu64
639 else
640 pkgsCross.aarch64-multiplatform;
641 in
642 crossPkgs.dockerTools.buildImage {
643 name = "hello-cross";
644 tag = "latest";
645 copyToRoot = pkgs.buildEnv {
646 name = "image-root";
647 pathsToLink = [ "/bin" ];
648 paths = [ crossPkgs.hello ];
649 };
650 };
651
652 # layered image where a store path is itself a symlink
653 layeredStoreSymlink =
654 let
655 target = pkgs.writeTextDir "dir/target" "Content doesn't matter.";
656 symlink = pkgs.runCommand "symlink" { } "ln -s ${target} $out";
657 in
658 pkgs.dockerTools.buildLayeredImage {
659 name = "layeredstoresymlink";
660 tag = "latest";
661 contents = [
662 pkgs.bash
663 symlink
664 ];
665 }
666 // {
667 passthru = { inherit symlink; };
668 };
669
670 # image with registry/ prefix
671 prefixedImage = pkgs.dockerTools.buildImage {
672 name = "registry-1.docker.io/image";
673 tag = "latest";
674 config.Cmd = [ "${pkgs.hello}/bin/hello" ];
675 };
676
677 # layered image with registry/ prefix
678 prefixedLayeredImage = pkgs.dockerTools.buildLayeredImage {
679 name = "registry-1.docker.io/layered-image";
680 tag = "latest";
681 config.Cmd = [ "${pkgs.hello}/bin/hello" ];
682 };
683
684 # layered image with files owned by a user other than root
685 layeredImageWithFakeRootCommands = pkgs.dockerTools.buildLayeredImage {
686 name = "layered-image-with-fake-root-commands";
687 tag = "latest";
688 contents = [
689 pkgs.pkgsStatic.busybox
690 ];
691 fakeRootCommands = ''
692 mkdir -p ./home/alice
693 chown 1000 ./home/alice
694 ln -s ${
695 pkgs.hello.overrideAttrs (
696 finalAttrs: prevAttrs: {
697 # A unique `hello` to make sure that it isn't included via another mechanism by accident.
698 configureFlags = prevAttrs.configureFlags or [ ] ++ [
699 " --program-prefix=layeredImageWithFakeRootCommands-"
700 ];
701 doCheck = false;
702 versionCheckProgram = "${builtins.placeholder "out"}/bin/${finalAttrs.meta.mainProgram}";
703 meta = prevAttrs.meta // {
704 mainProgram = "layeredImageWithFakeRootCommands-hello";
705 };
706 }
707 )
708 } ./hello
709 '';
710 };
711
712 # tarball consisting of both bash and redis images
713 mergedBashAndRedis = pkgs.dockerTools.mergeImages [
714 bash
715 redis
716 ];
717
718 # tarball consisting of bash (without tag) and redis images
719 mergedBashNoTagAndRedis = pkgs.dockerTools.mergeImages [
720 bashNoTag
721 redis
722 ];
723
724 # tarball consisting of bash and layered image with different owner of the
725 # /home/alice directory
726 mergedBashFakeRoot = pkgs.dockerTools.mergeImages [
727 bash
728 layeredImageWithFakeRootCommands
729 ];
730
731 mergeVaryingCompressor = pkgs.dockerTools.mergeImages [
732 redis
733 bashUncompressed
734 bashZstdCompressed
735 ];
736
737 helloOnRoot = pkgs.dockerTools.streamLayeredImage {
738 name = "hello";
739 tag = "latest";
740 contents = [
741 (pkgs.buildEnv {
742 name = "hello-root";
743 paths = [ pkgs.hello ];
744 })
745 ];
746 config.Cmd = [ "hello" ];
747 };
748
749 helloOnRootNoStore = pkgs.dockerTools.streamLayeredImage {
750 name = "hello";
751 tag = "latest";
752 contents = [
753 (pkgs.buildEnv {
754 name = "hello-root";
755 paths = [ pkgs.hello ];
756 })
757 ];
758 config.Cmd = [ "hello" ];
759 includeStorePaths = false;
760 };
761
762 helloOnRootNoStoreFakechroot = pkgs.dockerTools.streamLayeredImage {
763 name = "hello";
764 tag = "latest";
765 contents = [
766 (pkgs.buildEnv {
767 name = "hello-root";
768 paths = [ pkgs.hello ];
769 })
770 ];
771 config.Cmd = [ "hello" ];
772 includeStorePaths = false;
773 enableFakechroot = true;
774 };
775
776 etc =
777 let
778 inherit (pkgs) lib;
779 nixosCore = (
780 evalMinimalConfig (
781 { config, ... }:
782 {
783 imports = [
784 pkgs.pkgsModule
785 ../../../nixos/modules/system/etc/etc.nix
786 ];
787 environment.etc."some-config-file" = {
788 text = ''
789 127.0.0.1 localhost
790 ::1 localhost
791 '';
792 # For executables:
793 # mode = "0755";
794 };
795 }
796 )
797 );
798 in
799 pkgs.dockerTools.streamLayeredImage {
800 name = "etc";
801 tag = "latest";
802 enableFakechroot = true;
803 fakeRootCommands = ''
804 mkdir -p /etc
805 ${nixosCore.config.system.build.etcActivationCommands}
806 '';
807 config.Cmd = pkgs.writeScript "etc-cmd" ''
808 #!${pkgs.busybox}/bin/sh
809 ${pkgs.busybox}/bin/cat /etc/some-config-file
810 '';
811 };
812
813 # Example export of the bash image
814 exportBash = pkgs.dockerTools.exportImage { fromImage = bash; };
815
816 imageViaFakeChroot = pkgs.dockerTools.streamLayeredImage {
817 name = "image-via-fake-chroot";
818 tag = "latest";
819 config.Cmd = [ "hello" ];
820 enableFakechroot = true;
821 # Crucially, instead of a relative path, this creates /bin, which is
822 # intercepted by fakechroot.
823 # This functionality is not available on darwin as of 2021.
824 fakeRootCommands = ''
825 mkdir /bin
826 ln -s ${pkgs.hello}/bin/hello /bin/hello
827 '';
828 };
829
830 build-image-with-path = buildImage {
831 name = "build-image-with-path";
832 tag = "latest";
833 # Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
834 copyToRoot = [
835 pkgs.bashInteractive
836 ./test-dummy
837 ];
838 };
839
840 layered-image-with-path = pkgs.dockerTools.streamLayeredImage {
841 name = "layered-image-with-path";
842 tag = "latest";
843 contents = [
844 pkgs.bashInteractive
845 ./test-dummy
846 ];
847 };
848
849 build-image-with-architecture = buildImage {
850 name = "build-image-with-architecture";
851 tag = "latest";
852 architecture = "arm64";
853 # Not recommended. Use `buildEnv` between copy and packages to avoid file duplication.
854 copyToRoot = [
855 pkgs.bashInteractive
856 ./test-dummy
857 ];
858 };
859
860 layered-image-with-architecture = pkgs.dockerTools.streamLayeredImage {
861 name = "layered-image-with-architecture";
862 tag = "latest";
863 architecture = "arm64";
864 contents = [
865 pkgs.bashInteractive
866 ./test-dummy
867 ];
868 };
869
870 # ensure that caCertificates builds
871 image-with-certs = buildImage {
872 name = "image-with-certs";
873 tag = "latest";
874
875 copyToRoot = pkgs.buildEnv {
876 name = "image-with-certs-root";
877 paths = [
878 pkgs.coreutils
879 pkgs.dockerTools.caCertificates
880 ];
881 };
882
883 config = {
884 };
885 };
886
887 nix-shell-basic = streamNixShellImage {
888 name = "nix-shell-basic";
889 tag = "latest";
890 drv = pkgs.hello;
891 };
892
893 nix-shell-hook = streamNixShellImage {
894 name = "nix-shell-hook";
895 tag = "latest";
896 drv = pkgs.mkShell {
897 shellHook = ''
898 echo "This is the shell hook!"
899 exit
900 '';
901 };
902 };
903
904 nix-shell-inputs = streamNixShellImage {
905 name = "nix-shell-inputs";
906 tag = "latest";
907 drv = pkgs.mkShell {
908 nativeBuildInputs = [
909 pkgs.hello
910 ];
911 };
912 command = ''
913 hello
914 '';
915 };
916
917 nix-shell-pass-as-file = streamNixShellImage {
918 name = "nix-shell-pass-as-file";
919 tag = "latest";
920 drv = pkgs.mkShell {
921 str = "this is a string";
922 passAsFile = [ "str" ];
923 };
924 command = ''
925 cat "$strPath"
926 '';
927 };
928
929 nix-shell-run = streamNixShellImage {
930 name = "nix-shell-run";
931 tag = "latest";
932 drv = pkgs.mkShell { };
933 run = ''
934 case "$-" in
935 *i*) echo This shell is interactive ;;
936 *) echo This shell is not interactive ;;
937 esac
938 '';
939 };
940
941 nix-shell-command = streamNixShellImage {
942 name = "nix-shell-command";
943 tag = "latest";
944 drv = pkgs.mkShell { };
945 command = ''
946 case "$-" in
947 *i*) echo This shell is interactive ;;
948 *) echo This shell is not interactive ;;
949 esac
950 '';
951 };
952
953 nix-shell-writable-home = streamNixShellImage {
954 name = "nix-shell-writable-home";
955 tag = "latest";
956 drv = pkgs.mkShell { };
957 run = ''
958 if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then
959 echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))"
960 exit 1
961 fi
962
963 if ! touch $HOME/test-file; then
964 echo "home directory is not writable"
965 exit 1
966 fi
967 echo "home directory is writable"
968 '';
969 };
970
971 nix-shell-nonexistent-home = streamNixShellImage {
972 name = "nix-shell-nonexistent-home";
973 tag = "latest";
974 drv = pkgs.mkShell { };
975 homeDirectory = "/homeless-shelter";
976 run = ''
977 if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then
978 echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))"
979 exit 1
980 fi
981
982 if -e $HOME; then
983 echo "home directory exists"
984 exit 1
985 fi
986 echo "home directory doesn't exist"
987 '';
988 };
989
990 nix-shell-build-derivation = streamNixShellImage {
991 name = "nix-shell-build-derivation";
992 tag = "latest";
993 drv = pkgs.hello;
994 run = ''
995 buildDerivation
996 $out/bin/hello
997 '';
998 };
999
1000 nix-layered = pkgs.dockerTools.streamLayeredImage {
1001 name = "nix-layered";
1002 tag = "latest";
1003 contents = [
1004 pkgs.nix
1005 pkgs.bash
1006 ];
1007 includeNixDB = true;
1008 config = {
1009 Env = [
1010 "NIX_PAGER=cat"
1011 ];
1012 };
1013 };
1014
1015}