Nix

Reproducibility speedrun

Pablo COVES

Human Talk - Grenoble :: 2024-06-11

What is nix ?

  • A language ?
  • A package manager ?
  • An operating system ?
Yes !

A language

  • Functional
  • Pure
  • Declarative
  • Lazy

Domain specific

The nix language solves one problem : the creation and composition of derivations

A derivation ?

  • A recipe to build a package and its dependencies
  • The evaluation of a derivation returns a store path
  • The instanciation of a derivation builds the package

A package manager

Where nix really shines

Run a program

$ nix run nixpkgs#hello
Hello, world!

What happened ?

  • Nix fetched the hello derivation
  • It then evaluated and instantiated it
  • To finally run the program at the store path

What’s so special ?

Nix downloads and builds the package in an isolated environment

$ nix eval nixpkgs#hello.outPath
"/nix/store/g9r8k42vkx4sh4689rig1mwcnnic6z7d-hello-2.12.1"

/nix/store/$HASH-$PACKAGE-$VERSION

How to ensure reproducibility ?

$ nix run nixpkgs/ac314c2c5c82685447deec12be65daac77503466#hello
[* MiB DL] copying «github:NixOS/nixpkgs/ac3...466» to the store
  • Inputs are now fixed to a specific commit of the nixpkgs repository
  • Nix being pure, the same derivation will always yield the same store path

Development environment

A handy way to share project-specific environments from one machine to another

Nix flake

{
    inputs = {
        nixpkgs.url = "github:NixOS/nixpkgs";
        flake-utils.url = "github:numtide/flake-utils";
    };

    outputs = {nixpkgs, flake-utils, ...}:
        flake-utils.lib.eachDefaultSystem (system:
        let pkgs = import nixpkgs { inherit system; };
        in with pkgs; {
            devShells.default = mkShell { packages = [hello]; };
        }
    );
}

Free reproducibility

  • A flake.lock file is generated on the first run,
  • It contains the exact inputs used to build the environment
  • And can be shared with others or updated to get the latest version of the inputs

Let’s make our own

packages.human_talk = stdenv.mkDerivation {
    name = "human_talk";
    src = ./.;

    buildPhase = ''
        echo "#!{bash}/bin/bash" >> $name
        echo "echo Hello, world" >> $name
        chmod +x $name
    '';

    installPhase = ''
        mkdir -p $out/bin
        cp $name $out/bin/$name
    '';
};
nix run .#human_talk
Hello, world

Fun fact

This very presentation was built with nix using pandoc and reveal.js

An operating system

  • NixOS is a Linux distribution that is configured using the nix language
  • Nix Darwin is the same but on top macOS

Inputs first

inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
};

Outputs last

outputs = { nixpkgs, ... }: {
    nixosConfigurations.$HOSTNAME = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [ ./configuration.nix ];
    };
};

nixos-rebuild switch --flake .#HOSTNAME

Configuration.nix ?

This is where the magic happens

Packages

environment = {
    systemPackages = with pkgs; [git neovim];
    variables.EDITOR = "nvim";
};

Those packages and settings will be available system-wide

Services

services.openssh = {
    enable = true;
    ports = [ 22 ];
};

Services will be started at boot time

Users

users.users.alice = {
    isNormalUser  = true;
    home  = "/home/alice";
    description  = "Foo bar baz";
    extraGroups  = [ "wheel" ];
    openssh.authorizedKeys.keys  = [ "ssh-dss AAAAB3Nza..." ];
};

There is more

  • Home-manager allows to manage user configuration
  • Nix can be used to build Docker images without a Dockerfile

Questions ?

https://gitlab.com/pcoves/human-talks_nix