nix

a quick intro

Problem

What we need

  • make builds exactly the same every time
  • run the builds with deps it needs
  • replicate it on other machines

We need the ability to...

Solution we have...

  • installs deps in isolation
  • easy to reproduce env
  • easy to replicate

the goods about it...

Solutions we have...

  • it is too isolated
  • layered architecture
  • easy to reproduce env
  • image contains unwanted stuff
  • no concept of multiple image inheritance

the bads about it...

lets discuss

FROM node:16.16.0-slim
RUN node -v

# but i need `python` as well...

...but one year later

debian decided to replace python 2.7 with 3.11... 😬

its not so reproducible after all

FROM node:16.16.0-slim
RUN node -v

RUN apt update && apt install -y python
RUN python --version

# good, i got `python` now!

unwanted stuff can caused bigger images

FROM node:16.16.0-slim
RUN node -v

RUN apt update && apt install -y python git
RUN python --version
RUN git -v

# good, i got `python` and `git` now!

# but hey, why do i have `ssh`?
RUN ssh

wouldn't it be nice if I could do this instead?

FROM node:16.16.0, python:2.7, git:x.y.z

RUN node -v
RUN python --version
RUN git -v

nix

presenting you...

A build tool, package manager, and programming language

Software is a graph of dependencies.

Normally, this graph is implicit.

Nix makes is explicit.

Nix Store

Derivations

Sandbox

Language

Nix Store

/nix/store      graph
/nix/store/*    immutable nodes

Sample Node

/nix/store/4qnmjqc4z7wc058bj79gc2ppbs1dj1cx-nodejs-18.12.1

Derivations

  • Special entry in Nix Store
  • Describes how to build other entries in Nix Store
$ cat /nix/store/ynzfmamryf61rybjy1zqp1x19015yiy5-demo.drv   <-- note .drv

Derive([("out","/nix/store/76gxh82dqh6gcppm58ppbsi0h5hahj07-demo","","")],
[],[],"x86_64-darwin","/bin/sh",["-c","echo 'hello world'" > $out"],
[("builder","/nix/store/5arhyyfgnfs01n1cgaf7s82ckzys3vbg-bash-4.4-p23/bin/bash"),
("name","demo"),("out","/nix/store/76gxh82dqh6gcppm58ppbsi0h5hahj07-demo"),
("system","x86_64-darwin")])

All inputs/outputs are mentioned in a Derivation

Derivations

$ cat /nix/store/ynzfmamryf61rybjy1zqp1x19015yiy5-demo.drv

Derive(
  ### outputs
  [
    ("out","/nix/store/76gxh82dqh6gcppm58ppbsi0h5hahj07-demo","","")
  ],
  ### inputDrvs
  [],
  ### inputSrcs
  [],
  ### platform
  "x86_64-darwin",
  ### builder
  "/bin/sh",
  ### args
  ["-c","echo 'hello world'" > $out"],
  ### env
  [
    ("builder","/nix/store/5arhyyfgnfs01n1cgaf7s82ckzys3vbg-bash-4.4-p23/bin/bash"),
    ("name","demo"),
    ("out","/nix/store/76gxh82dqh6gcppm58ppbsi0h5hahj07-demo"),
    ("system","x86_64-darwin")
  ]
)

Derivations

$ nix-build /nix/store/ynzfmamryf61rybjy1zqp1x19015yiy5-demo.drv
/nix/store/76gxh82dqh6gcppm58ppbsi0h5hahj07-demo

$ cat /nix/store/76gxh82dqh6gcppm58ppbsi0h5hahj07-demo
hello world

Sandbox

Content from Derivation:

  • outputs
  • inputDrvs
  • inputSrcs
  • platform
  • builder
  • args
  • env

Anything that is needed to build, must be explicit
and must come from Nix Store!

Sandbox

Things either work

everywhere and always

or

nowhere and never

Language

  • lazy
  • pure
  • functional
let
  data = {
    a = 1;
    b = functionThatTakesNMinutesToRun 3;
  };
in data.a  => 1 (instantly)

Language

Use of Nix Language

  • Setup development environments
  • Create Derivations
derivation {
  name = "demo";
  builder = "${bash}/bin/bash";
  args = [ "-c" "echo neat > $out" ];
  system = "x86_64-darwin";
}

# creates /nix/store/ynzfmamryf61rybjy1zqp1x19015yiy5-demo.drv

It won't replace

Docker 🙈

but can make the two, better together

Questions?

nix

By Ali Yousuf