A look at Nix and Guix
Nix and Guix are a pair of unusual package managers based on the idea of declarative configurations. Their associated Linux distributions — NixOS and the Guix System — take the idea further by allowing users to define a single centralized configuration describing the state of the entire system. Both have been previously mentioned on LWN, but not covered extensively. They offer different takes on the central idea of treating packages like immutable values.
In a normal Linux distribution, the set of packages, services, and configuration files installed on a system is built up over time using tools that do not inherently require knowledge of programming. This approach can be convenient, making it possible to simply install a missing package and then have access to it going forward. The downside of this approach is how difficult it makes reconstructing a new system with the same set of tools, services, and tweaks when it comes time to migrate to a new host. The majority of Linux distributions lack any kind of centralized record of why each package was installed or each configuration option was changed.
NixOS and Guix offer an alternative: specify your setup with a programmable configuration file, and then let the package manager arrange for the software available on the system to reflect that. These configurations can include comments, version control, and the ability to factor out common parts for different machines, making it much easier to keep track of why something was configured or installed.
The key idea
Nix is a
"purely functional package manager
". Unlike other package managers, Nix
uses a
general programming language of the same name for configuration, albeit one
optimized for the task of describing packages.
The Nix language takes inspiration from the
ML family of languages, Haskell in
particular. Like Haskell, Nix programs work with and produce immutable values
through composing functions (the "functional" part) that don't have side-effects
(the "pure" part). Evaluating a Nix program produces a set of build actions for
the runtime of the package manager to take, but does not itself build or install
anything.
Nix is also lazy, calculating only the information about the
produced values that actually ends up being required. This lets Nix programs
skip performing computations for optional dependencies that don't end up being used.
Each Nix program describes
a "derivation" — "a specification for running an
executable on precisely defined input files to repeatably produce output files
at uniquely determined file system paths.
"
Derivations describe a specific build task to perform, including all of the
necessary inputs to
the build task in the form of required dependencies, build tools, source code,
etc. Nix doesn't permit implicit dependencies between build tasks, requiring all
prerequisites to be specified explicitly.
The benefit of using this model is that the full state of the system is specified in the same place, using the same language. The configuration not only includes the installed packages, but also the configuration files destined for /etc, the systemd service files, the filesystem mounts, users, kernel configuration options, drivers, etc. For example, here is a configuration module for running nginx, which builds nginx, sets up its configuration files, sets up a systemd service for nginx itself, and creates systemd timers for renewing HTTPS certificates with LetsEncrypt:
# This whole file evaluates to a single function from a set of # arguments (config, lib, and pkgs are normally used, but there # can be more which are ignored, thus "...") to a set of configuration # values that themselves are used in calculating the build action for # the overall system. { config, lib, pkgs, ... }: { # ACME is the protocol that LetsEncrypt uses to give out certificates security.acme.acceptTerms = true; security.acme.defaults.email = "example@example.com"; services.nginx = { enable = true; # Options can enable a bundle of related, more detailed settings recommendedTlsSettings = true; recommendedOptimisation = true; recommendedGzipSettings = true; recommendedProxySettings = true; }; # nginx can serve multiple virtual hosts with their own configurations services.nginx.virtualHosts."www.example.com" = { http2 = true; enableACME = true; forceSSL = true; locations."/" = { root = "/var/www/example.com"; }; }; }
The code that actually implements these options is defined in nixpkgs, NixOS's package repository, in the same language as the rest of the configuration. Becoming truly proficient in Nix can take some time, but most configurations are relatively straightforward, and the NixOS manual provides examples of common setups. The options search or nix search command-line tool also let users search for configuration options and available packages.
Derivations are nearly all reproducible, with the same inputs generating the same outputs. Some packages still include randomness or information about the timing of the build, which foil reproducibility. Work is ongoing to patch these packages to reach the project's goal of fully reproducible builds. Combined with the fact that derivations record all of the inputs to the build process, this reproducibility allows the result of derivations to be cached. Nix keeps the cache of previously evaluated derivations under /nix/store/, indexed by the hash of the derivation's inputs.
Nixpkgs contains definitions for more than 80,000 packages. These packages are built, cached, and shared by Hydra, NixOS's build farm. So, despite the fact that a NixOS configuration describes how to obtain and build all of the selected software from scratch, if a user depends on the package definitions in nixpkgs, they are likely to be able to download a cached output for the derivation from Hydra. NixOS refers to itself as a mixed source/binary distribution because of this — users can build software from scratch (including tuning the build flags for their system, as can be done by Gentoo users), but most users just download binary versions of most of their packages, and know that they're getting the same result as having built from scratch.
Multiple versions
Another benefit of arranging for the system to be built in this way is the ability to depend on multiple versions of the same package. Because each derivation references its build inputs explicitly, there is no requirement that a single global version of a compiler or shared library exist that satisfies every dependent package's needs simultaneously. This makes it easier to keep older software with specific needs running, decreases the burden of updating every package in the ecosystem at once when there's a major update to a common dependency, and means that maintainers don't need to solve version conflicts. It is a bit of a double-edged sword, however, because it does mean that it is easy to depend on several versions of a package without meaning to, which can bloat the size of a NixOS installation.
Being able to keep multiple versions of packages actually extends to being able to keep multiple versions of the system's entire configuration. When re-building a system using Nix, the derivation of the previous configuration remains available, and can be switched to using the bootloader. Users can therefore upgrade fearlessly, because any problems introduced by trying a new configuration can be resolved by rebooting. By the same token, software that is only needed for a short time, such as to try out a new program or grab a seldom-used command-line tool, can be installed into a temporary environment without interfering with the overall system configuration.
It is difficult to overstate how useful this ability is in practice. It is often possible to put a Linux system into an unworkable state by doing something unusual. While a lot can be learned from troubleshooting these issues, it is inconvenient when what is needed is a functional system.
Referring to dependencies directly, the way NixOS does, causes problems with software not packaged for use on the distribution. Unlike a typical distribution, NixOS only uses /usr/bin for env, to permit running shell scripts that start with #!/usr/bin/env. Shell scripts or other programs that assume that system binaries will be available in /usr/bin or other standard locations usually need to be adapted to run on NixOS. There are some tools available to make a chroot environment that puts binaries in the expected places, however, so this is usually not much of a hassle.
Guix
The Nix approach to package management has its benefits, but the Nix language also has its quirks. Learning to use a new programming language on top of a new package-management philosophy may seem like a tall order. The Guix project is working to create a distribution that uses Nix-style package management, but using a more widely used, general, and consistent programming language: Scheme. Guix is a GNU project, and so it only packages free software (in contrast to Nix, which packages non-free software behind a configuration option). It also has many fewer contributors than Nix, and is somewhat younger as a project — Guix received its first commit in 2012, whereas Nix dates to 2003 — so the number of packages available in Guix is somewhat lower.
Despite this, Guix has made several interesting advances of its own, including fully bootstrappable builds. Guix is now capable of building itself almost entirely from source on x86_64, a major milestone for the project. Ekaitz Zárraga gave a talk at FOSDEM 2024 about extending that support to RISC-V. Guix also has some features that NixOS lacks, such as the ability to "graft" security updates onto a package. This lets a more up-to-date version of a runtime dependency of a package be substituted in (presumably to fix some security problem) without recompiling the dependent package. This permits rolling out security updates to fundamental libraries without waiting for the build farm to rebuild all of Guix's packages.
A section of a Guix configuration comparable to the Nix configuration given above would look like:
; Guix defines types and helper functions in their own Scheme modules (require (gnu services web) (gnu services certbot)) ; This hook sends a signal to nginx to make it re-load its configuration, ; including the updated HTTPS certificates (define %nginx-deploy-hook (program-file "nginx-deploy-hook" #~(let ((pid (call-with-input-file "/var/run/nginx/pid" read))) (kill pid SIGHUP)))) (define %my-nginx-service (service nginx-service-type (nginx-configuration (server-blocks (list (nginx-server-configuration (server-name '("www.example.com")) (root "/srv/http/www.example.com") (ssl-certificate "/etc/letsencrypt/live/www.example.com/fullchain.pem") (ssl-certificate-key "/etc/letsencrypt/live/www.example.com/privkey.pem"))))))) (define %my-certbot-service (service certbot-service-type (certbot-configuration (email "example@example.com") (certificates (list (certificate-configuration (domains '("www.example.com")) (deploy-hook %nginx-deploy-hook)))))))
This configuration has a few differences. For one thing, Guix uses GNU Shepherd as an init system, instead of systemd. For another, the code shown here is not a standalone file that is imported by the main configuration file. Instead, the user would need to import this file and then add %my-nginx-service and %my-certbot-service to the services list for their system configuration by hand.
Experimenting
Nix and Guix (the package managers) both work on other distributions. Some distributions, such as Ubuntu and Debian, provide packages for them. For users of other distributions, Nix provides installation instructions and uninstallation instructions. Guix only provides installation instructions, but maintainer Tobias Geerinckx-Rice helpfully notes that one can read the installer script to see what ought to be removed.
In either case, using the package managers on another distribution can be useful for creating temporary environments, even if they cannot provide whole-system configuration. Individual programming languages often provide a solution for temporary development environments (for example, Python's virtual environments). Many projects are now shipping a shell.nix file as a language-agnostic alternative, which can install dependencies not packaged by the language's package manager. Somewhat fewer ship a guix.scm file serving the same purpose, but several GNU projects do.
NixOS and Guix offer a compelling alternatives to traditional distributions by rethinking how package management can be done. Their design permits incredible flexibility, simplifying package management for distribution maintainers and giving users additional control over how their computers are configured, without sacrificing binary packaging. Despite this, it seems unlikely that either will replace traditional package managers, especially when other distributions are receiving some of the same benefits of reproducibility using other techniques.
Posted Feb 27, 2024 21:52 UTC (Tue)
by pj (subscriber, #4506)
[Link]
Posted Feb 27, 2024 23:19 UTC (Tue)
by old (subscriber, #154324)
[Link] (9 responses)
This is not true. The main "guix" channel (a channel is where packages definitions can be found), only has free softwares. However, users can add any channel they want. For example, the "nonguix" channel has all the usual non-free softwares someone might want, e.g. chrome, proprietary firmware, steam, etc.
Posted Feb 28, 2024 0:41 UTC (Wed)
by atai (subscriber, #10977)
[Link] (8 responses)
Posted Feb 28, 2024 1:08 UTC (Wed)
by old (subscriber, #154324)
[Link] (7 responses)
> (in contrast to Nix, which packages non-free software behind a configuration option)
but not asserting that the former can essentially do the same, because GNU.
Posted Feb 28, 2024 1:59 UTC (Wed)
by daroc (editor, #160859)
[Link] (6 responses)
I certainly didn't mean to malign Guix, and I apologize if it came across that way. In fact, I suspect that many people will find the fact that only free software is available by default a bonus. Yes, you certainly can use nonguix to get package definitions for non-free software. Even if that weren't the case, Guile is a full-fledged programming language — you could write your own package definitions that did whatever you wanted, including downloading and compiling non-free software.
However, I do think there's a meaningful difference. Trying to install a non-free package using Nix gets you a warning message prompting you to set nixpkgs.config.allowUnfree, because the packages are present in nixpkgs, just disabled. Trying to install a non-free package using Guix will get you the same error as trying to install any non-existent package, unless you track down and configure nonguix. And nonguix is not mentioned in any of the official Guix documentation, because the GNU project doesn't endorse using non-free software.
I don't think that this difference in behavior says anything about the capabilities or worth of the two projects, but it does say something different about their priorities and approaches.
Posted Feb 28, 2024 10:27 UTC (Wed)
by zimoun (guest, #136589)
[Link] (4 responses)
For what my opinion is worth, it seems better to speak about extensibility. Guix provides various mechanisms to extend it. Somehow, it embraces The Emacs Thesis -- see Guile manual [1]:
" [...] it is delightful to create composite programs based on an orthogonal kernel written in a low-level language together with a powerful, high-level extension language.
Extension languages foster extensible programs, programs which adapt readily to different users and to changing times."
Channels [2] are an example. They go from "non-free" programs as drivers to deal with some hardware requirements to specific tools [3] developed in scientific context.
There is a continuum from the package definition or system declaration to the core of Guix itself: all is Scheme or Domain-Specific Language (DSL) as Scheme easily allows. I think that is the main difference with Nix: a completely free core named GNU Guix that you can extend for your needs; you or a group of people sharing the same interests. :-)
Nix can be extended too, obviously. However, from what I have seen, it seems more scattered and less continuous. But I might have overlooked.
( There is still one non Scheme part: guix-daemon inherited from Nix. People are working to some non-C++ reimplementation )
1: https://www.gnu.org/software/guile/manual/html_node/The-E...
Posted Mar 11, 2024 18:48 UTC (Mon)
by Ivar (guest, #170136)
[Link]
The concepts of channels maps directly to Nix as well, there you could also define (and easily share!) and additions you've made using channels or flakes. The central package/configuration module repository, nixpkgs, exposes all of it's infrastructure to help you out with this.
The tooling itself doesn't treat nixpkgs differently from any other channel/flake, you could in theory use the primitives provided by the Nix language to recreate everything from scratch without it. There isn't much of a point to rewriting the entire universe, but its possible!
Posted Mar 21, 2024 19:34 UTC (Thu)
by jrw (subscriber, #69959)
[Link] (2 responses)
Posted Mar 22, 2024 1:50 UTC (Fri)
by jrw (subscriber, #69959)
[Link] (1 responses)
Posted Feb 28, 2024 11:30 UTC (Wed)
by Baughn (subscriber, #124425)
[Link]
People are also encouraged not to mention it, apparently.
My own dalliance with GuixSD started and ended with a visit to their IRC channel, where I attempted to figure out how I would make it work with my Nvidia GPU. I was told that wasn't possible, and have been a happy user of NixOS for many years.
Posted Feb 28, 2024 8:28 UTC (Wed)
by Foxboron (subscriber, #108330)
[Link] (8 responses)
This is perpetrating a myth I've been trying to point out for years at this point. NixOS contains almost 110,000 packages and they are probably testing less than 2000 of them.
The "path" metric used in the reproducible builds dashboard is also misleading as one derivation does not equal one path. They also contain `fetchUrl` static files pinned with hashes, which means the metric is comparing the reproducability of static files. This inflates the percentage.
Guix is doing better as they contain a much smaller package sets, but if you want a realistic metric there is always the Arch rebuilder. The debian rebuilder effort has sadly been stalling for a few years.
https://reproducible.archlinux.org/
https://github.com/fepitre/package-rebuilder?tab=readme-o...
Posted Feb 28, 2024 9:05 UTC (Wed)
by jpoiret (subscriber, #155078)
[Link]
Posted Feb 29, 2024 14:21 UTC (Thu)
by zimbatm (guest, #100783)
[Link] (1 responses)
There is some truth in the sense that some variance in reproducibility is removed when using Guix/Nix because of the build sandbox. It removes some classes of reproducibility.
But without all the effort that Debian, Arch and other distros have put into reproducibility, the above graph wouldn't be at ~95%. The real hero is the https://reproducible-builds.org/ project.
Posted Feb 29, 2024 19:43 UTC (Thu)
by Foxboron (subscriber, #108330)
[Link]
The fact that NixOS does other things, like setting timestamps to 0 and the like, is not a property of the sandbox itself.
Posted Mar 8, 2024 19:26 UTC (Fri)
by Nebucatnetzer (guest, #170097)
[Link] (4 responses)
[1]: https://telecom-paris.hal.science/LTCI/hal-04430009v1
Posted Mar 11, 2024 12:34 UTC (Mon)
by Foxboron (subscriber, #108330)
[Link] (3 responses)
Posted Mar 11, 2024 12:44 UTC (Mon)
by gioele (subscriber, #61675)
[Link] (2 responses)
This is a misreading of the paper.
The paper results are:
> Our results show that we can achieve 99.99% reproducibility of build environments over 7 010 516 packages coming from 200 historical revisions of Nixpkgs, the Nix package set. Additionally, we were able to rebuild 99.94% of the packages from a 6-year-old Nixpkgs revision, demonstrating that reproducibility of build environments is actually useful for software rebuildability.
"This experiment" is rebuilding 99.94% of all the packages of a 6-year-old revision of a distro. "Actual Linux distros", cannot reproducibly build that many packages today, nor are able to do that for older revisions.
Posted Mar 14, 2024 10:36 UTC (Thu)
by Foxboron (subscriber, #108330)
[Link] (1 responses)
From RQ1:
> Therefore, we adjust RQ1.2 slightly into: assessing whether we can reproduce identical output paths for all the jobs (as we can always retrieve historical Hydra output paths).
From RQ2:
>Besides, for now, we do not check for *bit-by-bit* reproducible builds [ 16 ]. Extending our evaluation to build more revisions and checking for reproducible builds are both part of our future plans
So they have redefined "reproducible builds" to mean "can we reproduce the build-paths" and schewed the Reproducible Builds definition to "bit-by-bit reproducible builds" which is just misleading and extremely dissapointing.
Posted Mar 14, 2024 10:46 UTC (Thu)
by Foxboron (subscriber, #108330)
[Link]
Equating this paper with reproducible builds is the mistake here, not them misusing any words.
Posted Feb 28, 2024 19:16 UTC (Wed)
by nrdxp (subscriber, #142443)
[Link]
With that said, the reliability and recoverability are just leagues ahead of anything else out there I've used, and for me at least, it was all well worth the trouble. Not to mention the fact that my configuration has been tracked in a git repo for all that time, so I have a consistent history of changes I can reference back to if I ever need to, and I always have my tools setup and configured the way I need them with basically no effort. I use a nix flake and the colmena deployment tool to track and deploy changes to several of my machines in different physical locales, and I use NixOS to configure a private nebula mesh to connect them all, so pushing changes when I fix a bug or add a feature to all my machines is as simple as a single command in most cases. I also use a small bit of terraform, via terragrunt, to manage some of my cloud VPSs, but Nix still does all the building and service configuration on those machines.
For years now, I have also been very interested/involved in bringing the power of Nix to the professional landscape, but here I feel it still has a bit of an uphill battle before it is fully viable. I am one of the coauthors of divnix/std, which started out as a way to bring the power of Nix to devops tooling (CI, container publishing, etc, etc). Honestly I think we were actually fairly successful and were using it in a professional setting for several years, however the friction added to onboarding new, and even some existing developers was enough that we had to scale back our usage of Nix to basically just providing a convenient devshell.
It's unfortunate because I think the power of the tool is sometimes overshadowed by the difficulties in the language or the inefficiencies in some of the code, particularly the network code when dealing with binary caches or remote build machines. This is enough that it causes a significantly different UX for users who are intimately familiar with its quirks vs those who are not.
Even so, it might be pertinent to point out that there is a small team of developers working to address some of these pains from the foundation via the Tvix project, which is essentially a full rewrite of Nix in Rust seeking to maintain compatibility with the Nix language while addressing some of the more painful aspects of the current C++ implementation.
It is still fairly early days for Tvix, so we'll just have to see if they end up being successful in some of their ambitious goals, but they already have a working and fairly performant evaluator, and an interesting, innovative nix store implementation that is capable of deduplicating data both at rest and in transit, which would be a significant win for the enterprise space.
I hope that we can see Nix, or at least the core ideas in some future form, become more and more mainstream in the coming decades. Once you get used to it, it is such a positive paradigm shift that it seems almost silly to do things by hand, similar to what IaC has done for the infrastructure provisioning and management space. But it is still not without it's warts, and I will continue to do my part to help address them where I can.
Posted Feb 29, 2024 14:31 UTC (Thu)
by shreyansdoshi (subscriber, #169964)
[Link]
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
2: https://guix.gnu.org/manual/devel/en/html_node/Channels.html
3: https://hpc.guix.info/channels
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix
A look at Nix and Guix