diff --git a/Notes.txt b/Notes.txt index 8ff8754a796d73ef5fc1b2413c0466e0b9f08bb2..97908c5992a34eecaeedbb828689cfc05aecf6d2 100644 --- a/Notes.txt +++ b/Notes.txt @@ -148,3 +148,16 @@ * Nix helps you make the same piece of software more than once. * What's so hard about that? * Software is fantastically complex + + +* Put all the code snippets into a gist +* replace almonds with xaos +* put example of running something you installed with `nix shell` +* explain `nix shell` more +* explain flakes +* explain language control flow +* may-lee + * how to see what packages are installed in a `nix shell` + * when installing to a profile? + +* Link to slide repo on last slide diff --git a/README.rst b/README.rst new file mode 100644 index 0000000000000000000000000000000000000000..d517ccddda2ea5bf32caebfdd7f44c81183b133a --- /dev/null +++ b/README.rst @@ -0,0 +1,10 @@ +Nix +=== + +This project contains a slide deck and notes for an introductory-level Nix presentation. + +To build the slide deck, use nix:: + + nix build + +The result will be at `result/nixos-part1-slides.html`. diff --git a/default.nix b/default.nix index edb6724370215809be0f18e0df32f55500af019b..c3688090301b7443e9c926d7afcd5ff51af8a591 100644 --- a/default.nix +++ b/default.nix @@ -18,7 +18,8 @@ pkgs.stdenv.mkDerivation rec { --resource-path $src \ --standalone \ --self-contained \ - --variable revealjs-url:file://${sources."reveal.js"} \ + --variable=revealjs-url:file://${sources."reveal.js"} \ + --variable=slideNumber:1 \ -t revealjs \ -o "$outpath" \ "$inpath" diff --git a/references b/references new file mode 100644 index 0000000000000000000000000000000000000000..7bf5ac1b0cf88cf63dbc605217785198572abcaf --- /dev/null +++ b/references @@ -0,0 +1,5 @@ +* These slides + + git clone https://whetstone.private.storage/jcalderone/nix-training-material.git + cd nix-training-material + nix build diff --git a/shell.nix b/shell.nix index b5d1f87e5512c3bf8ab5a1fdfff84aff82d086d6..e1d6b5e44512d3402b0145ed4f934d8fb2093f74 100644 --- a/shell.nix +++ b/shell.nix @@ -17,6 +17,10 @@ pkgs.mkShell { qemu-img create -f qcow2 nixstore.qcow 50G; ''; + boot-installer = '' + qemu-system-x86_64 -m 2048m -enable-kvm -cdrom ${ubuntu-mini-iso} -drive file=root.qcow,if=none,format=qcow2,id=root -drive file=nixstore.qcow,if=none,format=qcow2,id=store -device virtio-blk-pci,drive=root,bootindex=1 -device virtio-blk-pci,drive=store,bootindex=2 -nic user,id=eth0,hostfwd=tcp:127.0.0.1:2222-:22 + ''; + boot = '' qemu-system-x86_64 -m 2048m -enable-kvm -cdrom ${ubuntu-mini-iso} -drive file=root.qcow,if=none,format=qcow2,id=root -drive file=nixstore.qcow,if=none,format=qcow2,id=store -device virtio-blk-pci,drive=root,bootindex=1 -device virtio-blk-pci,drive=store,bootindex=2 -nic user,id=eth0,hostfwd=tcp:127.0.0.1:2222-:22 ''; diff --git a/src/hands-on-notes b/src/hands-on-notes new file mode 100644 index 0000000000000000000000000000000000000000..24a88cfa1cc5472cbeab0155f566fdff00207517 --- /dev/null +++ b/src/hands-on-notes @@ -0,0 +1,186 @@ +# nix search + +```sh +$ nix search nixpkgs almonds +* legacyPackages.x86_64-linux.almonds (3.6) + Fractal viewer +``` + +::: notes + +* `nix search` searches nixpkgs, the package tree, and shows matches +* there are a lot of packages, try searching for something +* mention xaos is prettier + +::: + +# nix profile install + +```sh +$ nix profile install nixpkgs#almonds +``` + +::: notes + +* Once you find a package one thing you can do is install it +* `nix profile` imperatively manages a "profile" +* a profile is a self-containing set of installed software +* each user has their own profile +* you can install software into the profile +* only when the profile is active is the software available + +::: + +# nix profile list + +```sh +$ nix profile list + flake:nixpkgs#legacyPackages.x86_64-linux.almonds github:NixOS/nixpkgs/... +``` + +::: notes + +* show what's installed in the profile +* the output is ... verbose +* but it shows you exactly what version of the package you have installed + +::: + +# nix profile remove + +```sh +$ nix profile remove legacyPackages.x86_64-linux.almonds +$ nix profile list +$ +``` + +::: notes + +* you can uninstall them too +* so far this is pretty normal stuff +* most package managers can do all this + though fewer can do per-user installs + +::: + +# nix profile history + +```sh +$ nix profile history +Version 6 (2022-03-01) <- 5: + flake:nixpkgs#legacyPackages.x86_64-linux.almonds: ∅ -> 3.6 + +Version 7 (2022-03-01) <- 6: + flake:nixpkgs#legacyPackages.x86_64-linux.almonds: 3.6 -> ∅ +``` + +::: notes + +* Here's a neat trick. +* Since profiles are self-contained it is easy to keep old version +* You can see previous versions of the profile +* You can see what changed between them + +::: + +# flakes / nix registry list + +::: notes + +* Maybe you noticed the word "flake" in the nix profile output +* I don't think we'll have time to explore flakes in depth today +* For now, if you think of a "flake" as a package tree (and nixpkgs as just one of many possible package trees) the rest should make sense + +::: + +# nix profile rollback + +```sh +$ nix profile rollback --to 6 +switching profile from version 7 to 6 +``` + +::: notes + +* And you can switch back to them. +* rollback is not limited to going backwards +* the expected use-case is that you break your environment somehow and want to get back to a working version + +::: + +# nix shell + +```sh +nix shell nixpkgs#almonds +``` + +::: notes + +* `nix shell` starts a new shell running a new disposable profile +* the new profile has the request packages installed in it +* exit the shell, the profile is forgotten, the packages are unavailable + +::: + +# shell.nix + +`shell.nix` +```nix +let pkgs = import <nixpkgs> {}; +in pkgs.stdenv.mkDerivation { + name = "shell-demo"; + shellHook = '' + echo "Hello world" + ''; +} +``` + +# How does Nix work? +### Derivations + +```nix +builtins.derivation { + name = "example-derivation"; + builder = builtins.toFile "builder.sh" "echo 'Hello, world'" + system = "x86_64-linux"; +} +``` + +::: notes +::: + +# How does Nix work? + +```include +{ stdenv }: +stdenv.mkDerivation { + name = "demo-derivation"; + src = ./demo; + phases = [ "installPhase" ]; + + installPhase = '' + mkdir $out + echo "Hello, world" > $out/greeting.txt + ''; +} +``` + +# Q & A + +* If you want more, let me know on Slack. +* + +# Installing NixOS on Debian + +```sh +$ sh <(curl -L https://nixos.org/nix/install) --daemon +[ a ton of output ] +``` + + +::: notes + +* `$ $boot` +* training / password + +::: diff --git a/src/nixos-part1-slides.md b/src/nixos-part1-slides.md index 4af9be505cee96987916c6c66177382170a2900b..e03d99c0f9b445fbd69fe5a3cac5715cec94d814 100644 --- a/src/nixos-part1-slides.md +++ b/src/nixos-part1-slides.md @@ -1,11 +1,15 @@ ---- -author: Jean-Paul Calderone -title: Nix -subtitle: Make Software Suck Less -date: 2022-03-03 ---- +# + +<div style="width: 100%"> +<div style="align: center">Nix</div> +<div style="align: center; font-size: 70%">Make Software Suck Less</div> + +<div style="font-size: 60%"> +<span style="float: left">Jean-Paul Calderone</span> +<span style="float: right">2022-03-03</span> +</div> -# Welcome +</div> ::: notes @@ -19,33 +23,37 @@ date: 2022-03-03 ::: # -## Why Nix? +## What is Nix for? ## What tools are provided? ## Install some stuff! ## How does it work? -## Make your own! +## Q & A ::: notes -Here's an overview of what we'll cover today. +* Here's an overview of what we'll cover today. +* I'll explain what it is and why that's interesting +* We'll look at the tools that it provides +* Then we'll do some hands-on activities using those tools +* Then if we have time we'll look behind the scenes a little to see how it works. ::: -# Why Nix? +# What is Nix for? ## Reproducible Builds ::: notes -* So, why? -* The reason I'll focus on today is reproducible builds. +* It /can/ be useful for a lot of different things. +* The unifying theme that I'm going to focus on today is its use in reproducible builds. ::: # ### -Reproducible *Builds* +*Builds*, Reproducible ```python def b2a(os): @@ -78,16 +86,18 @@ Nix helps you *build software*. # ### -*Reproducible* Builds +Builds, *Reproducible* ::: notes -* Once you have something hardware can execute, +* So what's the "reproducible" part? +* Well... +* After you build the software you might have some hardware execute it. * If your plan was good *and the build was correct* then the results might be useful. -* If your plan was good the build was *incorrect* then the results be less useful. +* If your plan was good and the build was *incorrect* then the results might be less useful. * If the build is different each time then it's hard to know if the results will be useful or not. -* What's the big deal? +* Why would the build be different each time? * Aren't computers good at doing the same thing over and over? ::: @@ -165,17 +175,35 @@ wormhole receive 3-eskimo-topmost # ### - +Does the plan specify the version of ... + +* the compiler, assembler, linker +* statically linked libraries +* the C library and other dynamically linked libraries +* the runtime linker itself +* the content of runtime configuration files ::: notes * Since the plan is so complex, we leave parts of it out. -* We often leave out details about ... -* versions of build-time tools (eg the C compiler) -* versions of runtime dependencies (eg libc) -* exact configurations for all those dependencies +* Here are some examples of pieces we often leave out of build plans +* Some of these are traditionally considered "build" dependencies and others "runtime" dependencies +* But that's kind of an arbitrary distinction +* They all influence what software is actually executed +* Variations in any of them lead to... +* variations in the software that is built leading to... +* variations in the ultimate execution result. + +::: + +# + + -* These pieces get satisfied by whatever happens to be in the build environment +::: notes + +* Of course the plan cannot be executed with missing pieces +* These pieces get satisfied by whatever happens to be in the environment * The consequence is each build has the opportunity to follow a completely unique plan - and produce a completely unique piece of software. @@ -201,28 +229,69 @@ Nix builds are *the same every time*. ::: notes +* Nix provides tools to make it easier to specify all of the pieces. +* and Nix requires all of the pieces be specified. + ::: -# What tools does Nix provide? +# What tools are provided? * NixOS * Nixpkgs * nix command line interface * the Nix language +::: notes + +* So let's talk about those tools. +* They can be grouped into roughly four areas +* Let's look at them one by one + +::: + # ### NixOS the Linux distro -* An OS install is the combination of: - * software packages and - * their configuration -* NixOS takes software packages from Nixpkgs and adds configuration. +A complete NixOS "plan". + +<div style="font-size: 90%; width: 150%"> +```nix +let + src = builtins.fetchTarball { + name = "nixpkgs"; + url = "https://t.ly/MxPy"; + sha256 = "162dywda2dvfj1248afxc45kcrg83appjd0nmdb541hl7rnncf02"; + }; + pkgs = import src { }; +in { + imports = [ + <nixpkgs/nixos/modules/virtualisation/amazon-image.nix> + ]; + ec2.hvm = true; + boot.kernel.sysctl = { "vm.swappiness" = 0; }; + environments.systemPackages = [ pkgs.git ]; +} +``` +</div> ::: notes -* What if your entire OS install were a reproducible build? +* What if your entire OS were the result of a reproducible build? * That's NixOS -* NixOS adds a reproducible configuration layer on top of packages from Nixpkgs. +* NixOS takes reproducible packages from nixpkgs +* and adds a reproducible configuration layer on top + +* This is a complete (if spartan) NixOS configuration +* It demonstrates supplying some configuration to the kernel +* And installing the git package system-wide +* This expression /fully/ and /reproducibly/ describes a NixOS installation + +* I don't expect the details of this slide to make sense right now +* Just consider - +* this is a lot of text for a slide but +* it's hardly any text at all for a complete Linux system definition. + +* Let's move on from NixOS for the moment ::: @@ -244,18 +313,36 @@ Nix builds are *the same every time*. ::: # -### Nix the command line tool +### Nix the expression language -* `nix-build` -* `nix-shell` -* `nix repl` -* (and others) +<div style="font-size: 90%; width: 150%"> +```nix +let + src = builtins.fetchTarball { + name = "nixpkgs"; + url = "https://t.ly/MxPy"; + sha256 = "162dywda2dvfj1248afxc45kcrg83appjd0nmdb541hl7rnncf02"; + }; + pkgs = import src { }; +in { + imports = [ + <nixpkgs/nixos/modules/virtualisation/amazon-image.nix> + ]; + ec2.hvm = true; + boot.kernel.sysctl = { "vm.swappiness" = 0; }; + environments.systemPackages = [ pkgs.git ]; +} +``` +</div> ::: notes -* There are a lot of tools to use and interact with Nix. -* Many of them interpret expressions in the Nix language. -* We'll use some in a minute. +* Here's that configuration again. +* This is written in Nix the language. +* This is a declarative, functional expression language. +* It's also pretty basic as such things go and could probably didn't need to be invented +* It's not strictly necessary for all uses of Nix but in some cases you do need to read or write it. +* So let's take a closer look! ::: @@ -263,156 +350,107 @@ Nix builds are *the same every time*. ### Nix the expression language ```nix -nix-repl> 0 +# A comment + +# An integer 0 -nix-repl> "Hello, world." -"Hello, world." +# A floating point +0.5 -nix-repl> [ 1 2 3 ] -[ 1 2 3 ] +# A text (mostly) string +"Hello, world." -nix-repl> { a = "b"; } -{ a = "b"; } +# A list of all of the above +[ 1 1.5 "2" ] ``` ::: notes -* It's an expression language. * Everything is an expression. -* An expression either is or evaluates to a simple value. +* An expression either is or evaluates to a value. +* Values are immutable. * Here's integers, strings, lists, "attribute sets" +* This output is from `nix repl` +* If you have nix installed, go ahead and try it out ::: # ### Nix the expression language -```nix -nix-repl> - let - add = x: y: x + y; - in - add 1 2 -3 -``` -::: notes - -* It's a functional language. -* (note, reformatted for readability) - -::: - -# -### Nix the expression language ```nix -nix-repl> - let - add = x: y: x + y; - add-one = add 1; - in - add-one 2 -3 -``` - -::: notes - -* It has partial application. -* It has functions and you can treat them as values. -* (note, reformatted for readability) - -::: - -# Hands-On -## nix-env - -```sh -nix search xaos -nix-env --install --attr nixos.xaos +# An attribute sets (attrsets) +{ a = "b"; } -nix-env --query +# A "recursive" attrset +rec { a = "b"; c = a; } -nix-env --uninstall xaos +# nesting notation +{ a.b = "c"; } -nix-env --list-generations -nix-env --rollback +# equivalent to +{ a = { b = "c"; }; } ``` ::: notes -* I assume you already have the Nix tools installed. -* `nix search` searches the package tree -* `nix-env` imperatively manages a "profile" -* you can install software into the profile -* uninstall -* query (ie, list what it contains) -* generations of a profile are automatically kept around -* list them, delete them, switch between them +* There is also a key/value mapping type. +* The keys are identifier, the values are arbitrary. +* There's support for self-referential sets +* And syntax to make nested sets more convenient +* Nix uses attrsets a lot. ::: -# Hands-On -## nix-shell +# +### Nix the expression language -```sh -nix-shell -p xaos +```nix +let + add-one = x: x + 1; +in + add-one 2 ``` ::: notes -* `nix-shell` starts a new shell that has the requested packages installed -* exit the shell, the packages are gone +* I mentioned it's a functional language. +* Functions are treated values +* Here's a function definition and application +* This also demonstrates the let/in expression +* The let/in expression binds the name "add dash one" to a function +* Then evaluates that function with an argument of 2 +* The result, of course, is 3 -::: +* This isn't the whole language of course but there are probably better ways + to learn the rest than from a slideshow. -# Hands-On -## nix-shell - -`shell.nix` -```nix -let pkgs = import <nixpkgs> {}; -in pkgs.stdenv.mkDerivation { - name = "shell-demo"; - shellHook = '' - echo "Hello world" - ''; -} -``` - -::: notes - -* +* Let's move on to the hands-on activity. ::: -# How does Nix work? -### Derivations +# +### Nix the command line tool -```nix -builtins.derivation { - name = "example-derivation"; - builder = builtins.toFile "builder.sh" "echo 'Hello, world'" - system = "x86_64-linux"; -} -``` +* `nix search` +* `nix profile` +* `nix shell` +* `nix repl` +* `nix build` +* (and others) ::: notes -::: -# How does Nix work? +* There are a lot of tools to use and interact with Nix. +* Many of them interpret expressions in the Nix language. +* Let's try using some -```include -{ stdenv }: -stdenv.mkDerivation { - name = "demo-derivation"; - src = ./demo; - phases = [ "installPhase" ]; +* STOP RECORDING +* STOP SCREEN SHARING +* SWITCH TO TRAINING VM +* START SCREEN SHARING - installPhase = '' - mkdir $out - echo "Hello, world" > $out/greeting.txt - ''; -} -``` +:::