Skip to content

sdsc-ordes/nix-workshop

Repository files navigation




Nix & NixOS Workshop

Caution

This workshop is currently under development and is not yet complete.

This workshop is structured in 2 parts

  • Part 1: Learn what a Nix DevShell is and how to extend it. It is designed to provide a minimal, hands-on introduction to how Nix works. While explanations are concise, they aim to be precise enough to help you grasp the objectives of this part.

    • Gain a basic understanding of the Nix language.
    • Learn what a flake.nix file is.
    • Understand what a Nix derivation is and how it materializes.
  • Part 2: Building and running a basic NixOS system.

    • Requires Part 1.
    • Configure and build a NixOS system.
    • Deploy it to a cloud VM.

Tip

Due to the lack of well-structured and centralized official documentation on Nix topics, many external links to additional reading materials and videos are provided. Learning Nix can be challenging, but we prioritize linking to official documentation whenever relevant. Some useful resources include:

Requirements

The basic requirements for working with this repository by using one of the following approaches:

  • Use your machine [recommended]

    Ensure that you have installed Nix and optionally direnv.

  • Use the container

    You can run most of the workshop inside the provided container by running in the root of this repository

    git clean -df
    
    podman run -it \
      --userns=keep-id \
      -v "$(pwd):/workspace" \
      -w /workspace \
      ghcr.io/sdsc-ordes/nix-workshop:latest

    or

    git clean -df
    
    docker run -it  \
      --user root \
      -v "$(pwd):/workspace" \
      -w /workspace \
      ghcr.io/sdsc-ordes/nix-workshop:latest
  • Use the devcontainer [

    A devcontainer setup is given in .devcontainer. You can start this with code. Adjust the devontainer.json if you are using docker instead of podman.

Part 1 - Nix, Flakes & Nix DevShell

Check the slides here.

Part 2 - NixOS

What is NixOS?

A NixOS derivation is created by a function inputs.nixpkgs.lib.nixosSystem which comes from the Nixpkgs Flake. The nixpkgs repository is the mono-repository which maintains more than 130'000 software packages. These packages are defined - by nothing more than (you guessed it) - Nix functions which return derivations.

The nixosSystem Function

The inputs.nixpkgs.lib.nixosSystem function will produce a derivation which you can evaluate. For example - in this repository's flake.nix - the attribute nixosConfigurations.x86_64-linux.vm-simple is such a function invocation and to evaluate it you can run:

nix eval ".#nixosConfigurations.vm-simple.config.system.build.toplevel"

or you better build it with

nix build ".#nixosConfigurations.vm-simple.config.system.build.toplevel"

which will take some time and the resulting Nix store path linked by ./result then contains the built OS:

tree -L 2 ./result

> ./result
> ├── activate
> ├── append-initrd-secrets -> /nix/store/ccyny0nr3a4dn5f864caj1nmvhkyz938-append-initrd-secrets/bin/append-initrd-secrets
> ├── bin
> │   └── switch-to-configuration
> ├── boot.json
> ├── configuration-name
> ├── dry-activate
> ├── etc -> /nix/store/34f7cw087r9js5c1f3snwra466p03rjv-etc/etc
> ├── extra-dependencies
> ├── firmware -> /nix/store/28a2j3qirvnzjrzwahgqpl6d83p4dibb-firmware/lib/firmware
> ├── init
> ├── init-interface-version
> ├── initrd -> /nix/store/rhk5xymxhaap08abmvy8fspcfm3ghyf1-initrd-linux-6.6.82/initrd
> ├── kernel -> /nix/store/7c8qjbmxyyyscapv46cprwg3h1i0ry8b-linux-6.6.82/bzImage
> ├── kernel-modules -> /nix/store/5r9yn7mgianbqlqdn649k647v7zn6k9w-linux-6.6.82-modules
> ├── kernel-params
> ├── nixos-version
> ├── specialisation
> ├── sw -> /nix/store/v71rhhllsl7av7nrkzb58snsb2c7fal1-system-path
> ├── system
> └── systemd -> /nix/store/w9qcpyhjrxsqrps91wkz8r4mqvg9zrxc-systemd-256.10

The above (to my best knowledge) in simple terms contains everything needed to boot into this NixOS system. An activation script activate prepares symlinks into the immutable /nix/store on folders like

  • /boot (kernel and bootloader),
  • /etc (system configuration files), -/var (variable data) ,
  • /run (ephemeral runtime data),
  • /home (home directories)
  • etc.

switch-to-configuration script also takes care to switch to the new system on a running system and restart the appropriate systemd services.

The next section explains how to build/run & understand a simple NixOS VM setup.

Build/Run & Understand a Simple VM

First familiar yourself with the commands on the justfile with by running just. The build and repl commands, we have covered in the introduction.

In this example we are going to build a simple VM with just a user nixos and without a graphical desktop environment.

cp ./.env.tmpl .env
## Modify the .env file to have `NIXOS_HOST=vm-simple`

Understand the Configuration

The ./nixos/hosts/vm-simple/default.nix contains one function which returns the NixOS system:

{ inputs, outputs, ... }:
inputs.nixpkgs.lib.nixosSystem {
  system = "x86_64-linux";
  modules = [
    ./hosts/vm/configuration.nix
  ];
  specialArgs = {
    inherit inputs outputs;
  };
}

The function call inputs.nixpkgs.lib.nixosSystem {...} is a function defined in nixpgs which will generate a Nix derivation.

When we instruct Nix to build this derivation, the derivation gets realized in the Nix store (e.g. in /nix/store).