I've recently taken an interest in NixOS after switching to Debian from Ubuntu about 2 years ago.
Could someone kindly enlighten me as to point [3]? Is the term "reproducible builds" used in the same context as NixOS? Otherwise stated, does this reflect the same goals? On the surface this seems to be the case, but I'm struggling to understand how Debian's approach compares/contrasts.
I quite like Debian, but the transactional approach to package management in NixOS is ... titillating...
Debian is currently leading the way on deterministic builds, I believe. I had a fork at one point that integrated most of the changes in NixOS to make the system tarball (what comes on ISOs) etc deterministic, but it fell to the wayside a few years ago as I lost time to work on NixOS (it works well enough on the servers I've had it on for a few years, after I put some work in).
However, there is another axis to this question that NixOS does address, which is "reproducibility". To clarify, for the purposes here, I define:
- Reproducibility: I can always create a copy of a system state, in terms of the set of steps taken to build it, given some known description.
- Deterministic: I can always exactly reproduce a copy of the system state, down to bit-for-bit replication.
To make this more explicit, by these definitions: NixOS is reproducible, but not currently deterministic (except for a few things like the kernel). Debian is becoming deterministic, but not reproducible. These do not imply each other in any direction, IMO, from the POV of a user.
The reason for this is because, in short, when you run `apt install foobar` on Debian, while you may exactly be able to build a bit for bit copy of `foobar-1.2.3`, exactly matching those results based on the Debian package, the result of actually performing `apt install foobar` is not deterministic.
Today I may run that command and install 1.2.3. Tomorrow it may install 1.2.4 if the maintainer updated `foobar`. In both cases, I could make a bit-for-bit replica of 1.2.3 or 1.2.4, given the Debian package descriptions. But I cannot, without pinning package mirrors explicitly, always ensure the act of running those commands gives the same result.
This is kind of a problem with systems like Docker, for example. Two people may run a Dockerfile running `apt install foobar` at two different times, and get completely different copies of `foobar`! So you have to base determinism on the Docker image, not on the description of the image (the Dockerfile). Because the image you built might not actually match whatever you deploy.
In NixOS, the entire 'system' is actually defined by a single Git repository (called 'nixpkgs'). That means if you and I both have Git revision 0x12345678 of Nixpkgs, and we have the same configuration file for our NixOS systems, `nix-env -i foobar` will always install the same version of foobar, as it was described in Nixpkgs, at that exact time.
In practice this means I can do awesome things, like configure my NixOS laptop in VMWare at first, get my configuration.nix right, pin down the right Nixpkgs version. Put new hard drive into laptop, start ISO, checkout right Nixpkgs git version, copy configuration.nix, hit 'nixos-install' and reboot. My laptop is now identical to what I had before. Obviously this is also great in production environments because developers can get essentially-identical setups to production environments.
Note the definition of 'reproducible' above: you will take the same steps to produce the output. This does not imply fully bit-for-bit determinism. That means if installing `foobar` requires running `gcc -O2 foobar.c -o foobar` and running `copy ./foobar /usr/bin/foobar` (roughly), both you and I will always take those exact steps to install it. But maybe `foobar.c` embedded the `__DATE__` macro into its source, so it is not bitwise deterministic.
NixOS has the story for reproducible builds right, straight from the design -- so bitwise determinism is "only" a matter of some work and not any philosophical hurdle. But it's naturally something that requires care and tooling to do correctly and there are some unresolved bits that meant I never got done with the original work. But it's nothing fundamental.
The Debian developers have really pushed a substantial amount of the work into doing all this and making these tasks feasible, fixing many upstream packages -- including helping get extensions to GCC (to make things like `__DATE__` always a specified constant for packagers), and writing lots of documentation[1]. They deserve much, much praise for this endeavor, IMO.
From a quick search a while back, NixOs determinism is lower than the Reproducible Build team efforts. They patch code to avoid all kinds of incidental variables in source (build dates, orderings).
Could someone kindly enlighten me as to point [3]? Is the term "reproducible builds" used in the same context as NixOS? Otherwise stated, does this reflect the same goals? On the surface this seems to be the case, but I'm struggling to understand how Debian's approach compares/contrasts.
I quite like Debian, but the transactional approach to package management in NixOS is ... titillating...