c't 13/2021
S. 96
Test & Beratung
Linux-Distribution NixOS

Rein funktional

Ein Blick auf die Linux-Distribution NixOS

Ein System, das auch beim Stromausfall während eines ­Updates konsistent bleibt sowie beliebiges Downgrading und ­gefahrloses Rumprobieren ­erlaubt – das Featureset der ­Linux-Distribution NixOS klingt fast zu schön, um wahr zu sein.

Von Sylvester Tremmel

Die Linux-Distribution NixOS hebt sich mit einem im mathematischen Sinne „funktionalen“ Paketmanager und einer deklarativen Systemkonfiguration von der Masse ab. Das System basiert auf dem Paketmanager Nix, von dem es auch seinen Namen und seine wesentlichen Vorteile und Eigenheiten erbt. Nix überschreibt grundsätzlich nichts und betrachtet jede Anpassung und jedes Update als neues, separates Paket. Dadurch wird der Status Quo auch durch fehlgeschlagene Aktualisierungen nicht gefährdet und Updates können beliebig zurückgenommen werden.

Nix

Um das zu erreichen, bricht Nix mit gewohnten Konventionen und speichert die Inhalte von Softwarepaketen nicht an üblichen Orten wie /usr/bin/, sondern unter /nix/store/, dem Nix-Store. Dort bekommt jedes Paket seinen eigenen Ordner, der mit einem länglichen Hash anfängt. Zum Beispiel befindet sich Firefox nicht unter /usr/bin/firefox, sondern unter /nix/store/wzrrs3zs9h10bajxgzdsf80j252m64l4-firefox-88.0.1/bin/firefox. Über ein mehrstufiges System von Symlinks stellt Nix sicher, dass man trotzdem einfach „firefox“ im Terminal eintippen kann und der Browser startet.

In den Hash fließen allerlei Informationen ein, die das Paket exakt definieren, unter anderem der Quellcode (genau dieser Programmversion), benötigte Abhängigkeiten, Compiler-Flags und so weiter. Einmal kompiliert, ist ein Paket unveränderlich. Das ähnelt einer Variable in der funktionalen Programmierung, deren Wert sich auch nicht verändern darf. Das ist einer der Gründe, warum die Entwickler Nix als „funktionalen“ Paketmanager bezeichnen.

Auch bei einem Update werden Pakete nicht verändert. Stattdessen legt Nix ein neues Paket mit einem anderen Hash an. Anschließend passt der Paketmanager die Symlinks an, sodass fortan normalerweise die neue Firefox-Version startet. Die alte ist aber nach wie vor vorhanden und ­benutzbar – verschiedene Versionen der ­gleichen Software parallel zu installieren ist mit Nix kein Problem.

Die vielen ­Lambdas im Logo sind ein Hinweis: Nix und NixOS ist etwas für Fans funktionaler Sprachen, deren theo­re­tische Grund­lage das Lambda-­Kalkül ist.

So vermeidet Nix auch Bibliothekskonflikte: Programm A braucht eine Bibliothek in Version 1.2, Programm B braucht aber Version 2.3, die nicht abwärtskompatibel ist? Kein Problem, auch solche ­Abhängigkeiten identifiziert Nix über ­Hashes. Beide Bibliotheksversionen können parallel installiert sein und beide Programme sehen jeweils die Version, die sie brauchen. Und wenn zwei Programme die genau gleiche Abhängigkeit erfordern, wird sie auch nur einmal vorgehalten.

Dass Nix nichts überschreibt, sondern neue Pakete anlegt und eventuell Symlinks umbiegt, bietet noch weitere Vorteile: Wenn ein Update nicht zufriedenstellend ausfällt, holt ein einfacher „rollback“ die alte Version zurück – sie war ja ohnehin nie wirklich weg. Und wenn man eine neue Version nur mal ausprobieren will, kann man sie installieren, ohne irgendwelche Links umzubiegen – das ermöglicht unbeschwertes Testen. Ein Garbage Collector erlaubt alte, unbenutzte Versionen auf­zuräumen, damit langfristig nicht die ­Festplatte vollläuft.

Übrigens muss Nix Pakete nicht unbedingt selbst kompilieren, Server mit sogenannten Binary-Caches (zum Beispiel cache.nixos.org) können fertige Pakete bereitstellen. Ein passender Hash garantiert ohnehin, dass es sich um die richtige Version, Architektur et cetera handelt.

NixOS

Bis hierhin sind die beschriebenen Vorteile schlicht Eigenschaften des Paketmanagers Nix. Den kann man sich auch unter herkömmlichen Linux-Distributionen oder macOS installieren (und parallel zum Standardmanager des Systems nutzen). NixOS geht einen Schritt weiter und lässt praktisch das gesamte System von Nix managen, samt Kernel und Systemkonfiguration – auf Wunsch einschließlich der angelegten Benutzer. Das dehnt die Vorteile von Nix auf das Betriebssystem aus: Eine neue Kernel-Konfiguration lässt sich gefahrlos ausprobieren, ein Systemupdate problemlos zurücknehmen und ein Testaccount auch wirklich nur testweise anlegen.

Allerdings brechen die Entwickler dafür mit diversen Traditionen. Zum Beispiel hält sich NixOS nicht an die unter Linux übliche Verzeichnisstruktur. Das erfordert Anpassungen an Programmen – die die NixOS-Entwickler übernehmen – und beim Nutzer, der umdenken muss. Programme liegen eben nicht unter /usr/bin/ und der Systemkonfigurationsordner /etc/ scheint nur auf den ersten Blick normal: Weil der Paketmanager auch die Konfiguration verwaltet, sind viele der Dateien und Ordner unter /etc/ in Wahrheit Symlinks in den Nix-Store. Sie sollten nicht editiert werden, schließlich geht Nix davon aus, dass Pakete unveränderlich sind.

NixOS nutzt eine mehrschichtige Symlinks, um Pakete und Systemzustände zu verwalten. Normalerweise merkt man davon wenig, aber der Befehl namei bringt die Symlink-Kette ans Licht.

Deklarative Systemkonfiguration

Stattdessen müssen sich NixOS-Nutzer näher damit vertraut machen, wie Nix ­Pakete beschreibt und in dieser Beschreibung auch ihre Systemkonfiguration abfassen. Die speichern sie in der Datei /etc/nixos/configuration.nix, woraus Nix ableitet, welche Pakete installiert und welche Konfigurationsdateien generiert werden müssen. Wenn man die Konfiguration ­angepasst hat, wendet der Befehl nixos-rebuild switch sie an. Falls das Ergebnis nicht zufriedenstellt, setzt nixos-rebuild switch --rollback das System wieder auf den alten Stand. Das klappt gut, das System zeigte nicht einmal dann Auffällig­keiten, als wir einen Rollback von Gnome 40 auf Version 3.38 durchführten.

Wer eine Konfigurationsänderung nur mal ausprobieren will, führt einfach nixos-rebuild test aus. Dann ist nach einem Neustart automatisch alles wieder beim Alten. Oder man ruft nixos-rebuild build-vm auf, um eine QEMU-basierte VM mit der neuen Konfiguration zu booten. Im Test streikte dabei allerdings Gnome in der VM, was an den Einstellungen der virtuellen Maschine gelegen haben könnte, oder daran, dass wir furchtlos den „unstable“-Zweig von NixOS einsetzten. Ansonsten war von dieser Wahl – die wir der aktuellen Softwareauswahl wegen getroffen hatten – nicht viel zu merken, das System lief stabil.

Falls doch große Probleme auftreten und das System nicht mehr richtig bootet, ist in der Regel auch das kein Problem: NixOS vermerkt jeden Stand im Bootmenü und erlaubt einfach eine ältere Version zu booten. Lediglich wenn der Bootmanager selbst in Mitleidenschaft gezogen wird, steht man vor ähnlichen Problemen wie unter anderen Distributionen.

Allerdings hat die Sache zwei Nachteile: Zum einen wird viel mühsam angeeignetes Wissen obsolet. Wer seinen SSH-Service konfigurieren will, muss nicht mehr wissen, wie man die Datei sshd_config editiert, sondern muss die passenden Optionen in der NixOS-Konfiguration nachschlagen. Dafür gibt es aber zum Glück eine Suche (siehe ct.de/yvs1).

Zum anderen muss man sich an die Syntax gewöhnen, in der Nix-Pakete und deshalb auch die NixOS-Konfiguration geschrieben werden. Das sind die durchaus gewöhnungsbedürftigen „Nix-Expres­sions“. Simple Ausdrücke wie eine Menge von Attributen sind noch gut lesbar:

{
  font = "Lat2-Terminus16";
  keyMap = "de";
}

Aber weil die Expressions auch viele andere Typen, Kontrollstrukturen wie if-then-else, Variablenzuweisungen, Funktionen und mehr erlauben, wird es schnell kompliziert. Tatsächlich sind Nix-Expressions eine domänenspezifische, rein funktionale Programmiersprache mit Lazy-­Evaluation und eher unüblicher Syntax. Der folgende Ausdruck definiert zum ­Beispiel eine Funktion, die zwei Werte ­addiert, und ruft die Funktion mit den Werten 3 und 4 auf:

({x, y}: x + y) {x = 3; y = 4;}

Das erlaubt komplexe Konstrukte, die viel Arbeit abnehmen können, gerade wenn man oft Systeme (um-)konfiguriert. Aber um größere Paketdefinitionen zu verstehen oder sogar selbst zu verfassen, muss man sich länger mit Nix und seinen Expressions beschäftigen. Dabei hilft die sehr gute Dokumentation von Nix und NixOS (alle Links unter ct.de/yvs1), die Nutzer sich trotz ihres Umfangs zu ­Gemüte führen sollten.

Wer auf den Geschmack kommt, kann mit Nix-Expressions auch die benutzerspezifische Konfiguration (also unter anderem die Dotfiles im Home-Ordner) managen, ein Bereich, den NixOS von Haus aus nicht abdeckt. Das Projekt „Home Manager“ rüstet diese Funktion nach, richtet sich aber ausdrücklich nicht an Nix-Neulinge.

Fazit

Es ist verlockend, das Betriebssystem, seine Konfiguration und die installierte Software über eine funktionale Sprache zu deklarieren. Für Linux-Neulinge ist NixOS aber definitiv nix und auch eingefleischtere Nutzer müssen umdenken und sich an Nix’ Syntax und vielleicht auch funktionale Programmierung insgesamt gewöhnen. Der Zeitpunkt dafür ist gut, bei Redak­tionsschluss war die neueste stabile Version 21.05 für den 28. Mai angekündigt. Wer sich auf NixOS einlässt, bekommt ein Betriebssystem, das zum Beispiel für Administratoren interessant ist, die viele Systeme und Konfigurationen verwalten. Auch Entwickler, insbesondere wenn sie oft Software ausprobieren und Linux-­Enthusiasten, die gerne tief in Ihrem System wühlen, sollten sich NixOS genauer ansehen. (syt@ct.de)

Dokumentationen: ct.de/yvs1

NixOS
Linux-Distribution
Hersteller Community um die NixOS Foundation
Lizenz Open Source (MIT, LGPL)
Preis kostenlos

Kommentieren