at master 1015 lines 27 kB view raw
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}