Making a Live OS for tooling (not install)

I’m looking to make a live OS that is not an installer, instead carrying a more traditional format and tooling useful at boot after auto login.

General reading:

That last one seems like it should work, but it doesn’t seem to function as advertised. For example, it says:

  • It is easy to add your own packages and configuration changes to the image.

OK, let’s do that. Let’s make a minimal ISO with some file in /opt. Just to start with something familiar, let’s do it in docker first. I added to a typical dockertools a pathsToLink with /opt and the path includes my new deriviation:

    fileInOpt = pkgs.stdenv.mkDerivation {
        name = "fileInOpt";
        src = ./.;
        phases = [ "unpackPhase" "installPhase" ];
        installPhase = ''
    mkdir -p $out/opt
    touch $out/opt/this_file_is_in_opt
''; };

After a quick nix-build thing.nix && docker load <result we can docker run --rm -it thing bash -c 'ls /opt' and see this_file_is_in_opt. All good.

Now for our ISO use case:

{ config, pkgs, ... }:

let fileInOpt = pkgs.stdenv.mkDerivation {
        name = "fileInOpt";
        src = ./.;
        phases = [ "unpackPhase" "installPhase" ];
        installPhase = ''
            mkdir -p $out/opt
            touch $out/opt/this_file_is_in_opt
''; };
in {
  imports = [
    <nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix>
  ];

  environment.systemPackages = [ fileInOpt ];
}

And building with nix-build '<nixpkgs/nixos>' -A config.system.build.isoImage -I nixos-config=nixos.nix. Can run in qemu, auto logs in (where is that config? Q for another day), and no /opt/. The package isn’t even in /nix/store.

We can add more “normal” packages and see they are available in /run/current-system/sw/, but how do I get a top level /opt? I’ll be studying build.isoImage for now.

1 Like

Docker images are the odd one out, nix packages in general cannot write to root, that’s just not how nix works. The docker tooling specifically builds images with the packages unrolled into root, since those aren’t really NixOS systems, and the whole NixOS system concept makes no sense in containers because their filesystems are immutable anyway.

I have no idea why your package is missing from the nix store though.

If you want to create a /opt, you’ll need to use system.activationScripts (or systemd.tmpfiles) to create it at boot, and copy/symlink some files to it. That’s how all files outside the nix store come into existence on NixOS.

1 Like

For creating such a toolbox ISO (that also allows installation) I am currently playing with the “official” approach to build a custom NixOS ISO as described in the manual (with slight changes to adjust it to flakes).

My current progress can be seen in feature: installer image by NobbZ · Pull Request #603 · NobbZ/nixos-config · GitHub, and I indeed named the branch installer and related outputs, as that was the plan when I begun.

Over time my plans did shift and now I want a more generic toolbox. For that I will probably add the related tooling over the next week, though I need to identify what I actually need, as another goal is, to keep the resulting image below 2 GiB.

This most likely comes from the fact that by default environment.pathsToLink does not list /opt.

That will only symlink the store paths to /var/run/current-system, not root, right?

Easy enough to try:

$ cat foo.nix
{ config, pkgs, ... }:

let fileInOpt = pkgs.stdenv.mkDerivation {
        name = "fileInOpt";
        src = ./.;
        phases = [ "unpackPhase" "installPhase" ];
        installPhase = ''
            mkdir -p $out/opt
            touch $out/opt/this_file_is_in_opt
''; };
in {
  imports = [
    <nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix>
  ];

  environment.pathsToLink = [ "/opt" ];
  environment.systemPackages = [ fileInOpt ];
}
$ nix-build foo.nix
$ qemu-system-x86_64 -nographic -cdrom result/iso/*.iso \
    -m 4G -display curses

(if you’re following along at home you probably want -kvm in the qemu command line)

And after boot:

[nixos@nixos:~]$ ls /opt
ls: cannot access '/opt': No such file or directory

[nixos@nixos:~]$ ls /run/current-system/sw/opt
this_file_is_in_opt

So yeah, not a fix.

@TLATER Yes, your suggestion is a fine workaround. Thank you for pointing out that field and the options search! So much I feel like I’m not learning a language (prims and norms) but a cookbook (libs and solution de jure), this will help.