General questions for a popularization article in France

Hi all,

Linux Pratique, a french magazine, has validated my draft of article (only the plan) about my experience on NixOS :blush:

While writing the article, I realized that some points are still not clear to me.

  1. Can we say that NixOS, in addition to the functional philosophy, has a top-down philosophy: it starts from the desired system configuration and handles all the steps to reach the destination ā€“ whatever is the initial state. Whereas, imperative distributions, have a bottom-up process, giving tools to move the current state of the system from one state to another until the destination is reached. Is it correct ?
  2. NixOS does not seem to be a rolling release like Arch Linux does. For instance, in configuration.nix there is a pinned system.stateVersion, currently 19.03. That leads me to a question: what are the breaking changes between versions ? Is it a bad point for NixOS compared to Arch Linux ? Does it imply that a user of NixOS will need to make a full re-installation at some point, to follow the last version ?
  3. If Iā€™m not mistaken, NixOS is able to build Docker images with rather minimal sizes. These docker images only include run-time dependencies, arenā€™t they ? Otherwise, what else do they contain ? Is it easy to build such minimal docker images ? How easy is it to build them compared to building images with multi stage builds ?

PM me if you want to know more about the article, or if you want to involve yourself, the aim is to develop the community in my country. I felt a bit alone on NixOS, colleagues were almost laughing at me because I was using a rather unknown distribution :roll_eyes: I wished that I could have shown them more articles in popular magazines.

11 Likes

Hello,

Itā€™s nice to see someone from a good french magazine interested in NixOS :+1:

I think you are correct with your first question. In particular the nixos-rebuild and nixos-install commands are idempotent, and will always result in the same system (if you are using the same commit of nixpkgs and the same system config).

The system.stateVersion variable is only used to pin some packages (like postgresql). It is used to prevent upgrades to versions not compatible with their current data format. The services affected by this variable are usually stated in the NixOS release notes, itā€™s also possible to grep the nixpkgs repo as there are not much package using this.

This variable is meant to never be changed, so to upgrade a system from version 18.09 to 19.03 you only have to update the channel (with the nix-channel command). It is however possible to use NixOS as a rolling release with the use of the nixos-unstable channel which is tracking the master branch of nixpkgs after automated tests are run.

About the docker image builder it will only contain the specified packages and their dependencies. To build one you have to create a .nix file with the corresponding derivation. More information here: Nixpkgs 23.11 manual | Nix & NixOS

I would be happy to see a good article on NixOS in a french magazine, if you have more information on the release date please tell me :slight_smile:

2 Likes

I first want to reiterate the already well made point: system.stateVersion is not the version of the installed system. It is the version of the ā€œstate schemaā€. It should not be changed after an installation, unless specified, and as of right now, it never was specified to do so, and development tries to ensure we never need to.


About rolling release, the nixos-unstable channel is kind of a rolling release, it ends up being forked and frozen for release in the release process. Many NixOS users are following nixos-unstable, and the fact that the testedtest suite has to pass on hydra to update the channel makes updates relatively safe.

In a way, NixOS has its cake and ate it too! (Le bœuf et lā€™argent du bœuf.) There is the stable release cut at regular intervals, for users desiring such a scheme, and there is the unstable channel, for users preferring something like a rolling release.


In addition, if you want to have me read your close to final draft, to verify informations, je peux bien, Ć©tant francophone de langue maternelle.

And thanks for writing words about the distribution for reaching out!

1 Like

In a way, NixOS has its cake and ate it too! (Le bœuf et lā€™argent du bœuf.) There is the stable release cut at regular intervals, for users desiring such a scheme, and there is the unstable channel, for users preferring something like a rolling release.

I would say that Ā«having the cake and eating it, tooĀ» would correspond to running a mix of software from stable and unstable channel (which is hard everywhere else and usually easy with Nix)

4 Likes

Oops! That was my first thought when writing that paragraph, but it got lost somewhere between my brain and my fingers. Yes, you can follow the stable release for your system, and pick and match what you need from the rolling release. There is where the beef is at :).

Hi jojo,
Thanks for this article.
Youā€™re not alone on NixOS in France. You may already know some articles on LinuxFR (Tous les contenus Ć©tiquetĆ©s avec Ā«Ā nixĀ Ā» - LinuxFr.org). I talked about Nix, in a french conference and in a french meet-up (https://juliendehos.gitlab.io/lillefp-2019-nix/). You can contact me if you want, maybe I can help.

2 Likes

Indeed. Iā€™ve not made the jump yet, but tried a few years ago and am motivated for this summerā€¦ Also, there is a #nixos-fr IRC channel on freenode with few people inside :wink:

1 Like

Hi all, thanks for your answers ! Previous points are clear to me now. Glad to be in touch with other people using NixOS. Thanks a lot @nyaloutre for your precise answers and @juliendehos for your links. Your work is fascinating and yes I knew posts and youtube videos from nokomprendo: I watched many and really liked them. Ok @yakulu I will join the IRC channel, see you soon there I guess. Help for review will be welcomed @samueldr :slight_smile:

Iā€™m still writing the article and I stumbled on a point (even if itā€™s a detail from my POV) concerning how NixOS handles different versions of the same package.

Letā€™s say that a package installs a binary ā€œfooā€ in the PATH. And letā€™s consider that we install two versions of this packages ā€œfoo-2.1ā€ and ā€œfoo-2.2ā€.

nix-env -iA foo22
nix-env -iA foo21

AFAIK the foo command will point to the foo21 binary, the last installed. (tested with python3.6 and python3.7)

What would happen if both packages were requested in systemPackages ? in the configuration.nix file. How would NixOS choose the package version that will be used by the foo command ? Is it the last one in the list of packages ?

Another question :

IIUC packages (or derivations) are stored in /nix/store/\<hash\>-\<package-name\>

The hash here is not the same as a hash used to check the downloaded sources, or is it ? Just to be sure. I guess the hash in the folder name is a hash that includes all derivation specifications, isnā€™t it ?

Last point :

Is it ok to use ā€œpackageā€ instead of ā€œderivationā€ in a popularization article ? Or does it misses a crucial point ?

If you try and install two packages that have the same binary, the second installation will fail with an error telling you that you need to set the meta.priority of one of the packages. This is definitely true for nix-env -iA. I havenā€™t tested this scenario with systemPackages but I have to assume a similar error shows up there.

If you define meta.priority on one of the packages to something non-default, then both packages can be installed at the same time, but the one with the higher priority (definedā€”counterintuitivelyā€”as a lower meta.priority value) is the one that ends up in your PATH. IIRC if the lower-priority package has files not present in the higher-priority package those files will still end up linked into your profile; which is to say, it resolves conflicts on a file-by-file basis rather than omitting the whole package.

If you donā€™t want to override a package to change its meta.priority you can also use e.g. nix-env --set-flag priority 5 foo21 to set the priority of foo21 to 5, but the problem with this approach is you can only use it on already-installed packages, so you have to install the one you want to have as lower priority, then set its priority, then install the one you want to have as higher priority.

All of this is assuming that the two packages actually have distinct names. If both packages have the same name but merely differ in version (as I assume python3.6 and python3.7 are) then the second installation will actually replace the first. You can use the --preserve-installed flag to nix-env to instruct it to not uninstall the old package first. This behavior is specific to nix-env; specifying both packages in systemPackages will try to install them both.

The hash is derived from the instantiated derivation. As for the downloaded sources, that actually ends up as a separate derivation with its own hash (which the package derivation then includes and therefore affects the package derivationā€™s hash). most sources are specified as fixed-output derivations, meaning the package definition says what the hash is (and then Nix checks it when it actually downloads the source), so the output hash can be calculated without downloading anything. For a non-fixed-output derivation, Nix has to actually fetch the source before it can calculate the output hash.

I donā€™t know about anyone else, but I use ā€œpackageā€ to refer to the whole package definition that declares the software, whereas ā€œderivationā€ is actually a specific technical term, where a package is usually comprised of at least 2 derivations (the package derivation and the nested derivation for the package sources). Informally you can use them interchangeably but I usually opt for ā€œpackageā€ in the informal context.

2 Likes

Thanks @lilyball. Iā€™m pleased to discover that Nix does handle precisely these use cases that are exceptions from my POV. The meaning of ā€œderivationā€ has been unclear for me for a long time.
Now I come to believe that ā€œderivationā€ just means ā€œsomething built from something elseā€.

Thus:

  • downloading a source from somewhere yields a derivation with just this source inside
  • building a package yields a derivation that includes derivations of the sources of the build and outputs of the build
  • ā€¦

If Iā€™m correct, one common point of Nix derivations is that each of them corresponds to a folder in the nix store. A path with the pattern : /nix/store/<hash>-<name>

Is it correct ?

Nice, we should publicize them more! Iā€™ve just created #nixos-it for Italian people.

Thatā€™s broadly correct. Multi-output derivations can actually have multiple out paths. For example, nixpkgs.tmux has 2 outputs, "out" and "man". The first output in the list ("out") is the default output you get when referencing the package, though nix-env can install multiple outputs (controlled by outputsToInstall). So on my machine nixpkgs.tmux.out has a store path of /nix/store/kg8qgbiwzs31452qi60bh117kgjyxnmw-tmux-2.9a but nixpkgs.tmux.man has a store path of /nix/store/kjp45n21af24qixlv2pc8h60rbkhqqga-tmux-2.9a-man.

When one derivation references another (such as a package referencing its source), the default output is whatā€™s actually used (in general, converting a derivation into a string produces the store path of its default output; this is literally how the src attribute works, itā€™s just converted into its store path and passed in the src environment variable to the builder of the outer derivation, and then the default builder unpacks the $src var into its own working directory prior to running any build steps).

But yes, ultimately, a derivation is a set of instructions for translating a set of inputs into one or more output paths, where all inputs and outputs are in the nix store. If a derivation references a path, the path is copied into the nix store during evaluation. The resulting .drv files are also stored in the nix store. The end result is if I take my /nix/store dir and copy that to a new machine (running the same system), that new machine now has everything necessary to run all of the software I had installed, and in the absence of garbage collection, to rebuild anything that I had previously built (if I run garbage collection all of the sources and build-time dependencies will be collected, leaving only the runtime dependencies of the packages I have currently or previously installed).

3 Likes

Just precising, that the default is the first element, in this case it is ā€œoutā€, which is the usual default. :slight_smile:

outputs = [ "lib" "headers" "doc" ];

[ā€¦]
The first element of outputs determines the default output. Thus, you could also write

buildInputs = [ pkg pkg.headers ];

since pkg is equivalent to pkg.lib .

2 Likes

Thatā€™s really interesting. IIUC, copying a nix store should work between same OSes at the same state : for instance between two debians with same installed system packages.

What does mean " the path is copied into the nix store during evaluation" ? What is copied ? Is it just a link ? Is it a copy of the string of the path ?

A nix store can also contain derivations for other OSes or for incompatible platforms for the same OS!

Itā€™s a lesser used use case, and not entirely supported right now, but if you cross-compile for 64-bit ARM (aarch64), derivations for aarch64 end up in the store. Though you donā€™t need to cross-compile for that!

As long as I donā€™t need to build something, or that there is an appropriate builder configured in the system, I can also have native builds from those foreign platforms in the store. Letā€™s pick GNU hello aarch64 from trunk, this is the latest build right now, trunk on hydra is what ends up being nixpkgs-unstable. Under details, there is Output store paths, copying this path, and building the command nix-store --realise /nix/store/46pgpyqya17npazqr6myb04lpw8jl9xs-hello-2.10, it will copy the build to your store.

~ $ file /nix/store/46pgpyqya17npazqr6myb04lpw8jl9xs-hello-2.10/bin/hello
/nix/store/46pgpyqya17npazqr6myb04lpw8jl9xs-hello-2.10/bin/hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /nix/store/0n01cc3r0sj56h2kmwr0lxha46afmsm9-glibc-2.27/lib/ld-linux-aarch64.so.1, for GNU/Linux 2.6.32, not stripped
~ $ /nix/store/46pgpyqya17npazqr6myb04lpw8jl9xs-hello-2.10/bin/hello
-bash: /nix/store/46pgpyqya17npazqr6myb04lpw8jl9xs-hello-2.10/bin/hello: cannot execute binary file: Exec format error

All this to say: there is nothing linked to the system state in the store (/nix/store). Though, under /nix/var/ there will be system-specific stuff, among others for system and user profiles.

1 Like

Ok, so, if I got it, a Nix store on a specific OS and specific architecture can be used to share derivation outputs for other OSes and other architectures. Really cool. I bet itā€™s handy for maintainers that compile packages aiming several distributions and several architectures.

To be even more succint, ā€œa Nix storeā€ does not ā€œcareā€ about the system. The system, is part of the inputs, meaning that the exact same package, built on a different system, will have a different hash. All this from the fact that the system affects the inputs. (Though, a source package wouldnā€™t differ, and other fixed output derivations similarly.)

1 Like

The contents of the path. If the path points at a file, the file is copied into the store (such that the resulting /nix/store/<hash>-basename is a copy of the file). The hash used here is a hash of the fileā€™s contents. If the path points at a directory, then the directory is copied into the store, and the hash comes from the NAR serialization of the directory. If it points at a symlink, the symlink is copied as-is into the store too. I donā€™t know what happens for other file types, probably an error.

2 Likes

Ok, wow, does it mean that NixOS uses a lot of space ? because of deep copying every folder referenced by a path ?

Thanks for introducing NAR serialization and archives. I didnā€™t know about it. That is smart. I didnā€™t even know that *.tar format has so many cons.

Nix is garbage-collected. It can certainly end up gobbling up gigabytes of space, but then you run nix-collect-garbage and a lot (probably most) of that will go away. You can also run nix-store --optimise if you like, which will scan your entire store and replace duplicate files with hardlinks.

3 Likes