Nix Package manager

Arian van Putten

Assumptions about my audience

Ask questions!

Build problems

A current state of affairs - (Raise hands if you had one of these issues!)

Challenge

What is the root cause of all these issues?

What is the root cause of all these issues?

Mutability

What do we want?

Digression - Git

Digression - Git

In Git, do we all edit the same directory? No!

 git log --graph --decorate --all
* commit 24c1ad70db1890dcc2b3dbaaa5a151adedaec0b9 (HEAD)
| Author: Arian van Putten <aeroboy94@gmail.com>
| Date:   Mon Jul 30 13:34:51 2018 +0200
| 
|     Implement feature C
| 
* commit 1e63d01b43dcdab7636f6e49a8c116b42dd7af8f
| Author: Arian van Putten <aeroboy94@gmail.com>
| Date:   Mon Jul 30 13:34:45 2018 +0200
| 
|     Implement feature A
| 
* commit b5deb132c92bb39e99477432b62adea62dcca43c
Author: Arian van Putten <aeroboy94@gmail.com>
Date:   Mon Jul 30 13:34:35 2018 +0200

    Initial commit

Digression - Git

commit-id(Implement feature A) =
  sha1(.
        ├── sha1(a)
        ├── sha1(b
        │        └── sha1(b.html))
        └── sha1(c
                └── sha1(a.java))

$ tree ./git/objects/24c1ad70db1890dcc2b3dbaaa5a151adedaec0b9
  ./git/objects/24c1ad70db1890dcc2b3dbaaa5a151adedaec0b9
  ├── a
  ├── b
  │   └── b.html
  └── c
      └── a.java

P.S. I know I am lying a bit, but this is morally true

Digression - Git

We simply change to which commit HEAD points, to rollback

 git log --graph --decorate --all
* commit 24c1ad70db1890dcc2b3dbaaa5a151adedaec0b9 (HEAD)
| Author: Arian van Putten <aeroboy94@gmail.com>
| Date:   Mon Jul 30 13:34:51 2018 +0200
| 
|     Implement feature C
| 
* commit 1e63d01b43dcdab7636f6e49a8c116b42dd7af8f
| Author: Arian van Putten <aeroboy94@gmail.com>
| Date:   Mon Jul 30 13:34:45 2018 +0200
| 
|     Implement feature A
| 
* commit b5deb132c92bb39e99477432b62adea62dcca43c
Author: Arian van Putten <aeroboy94@gmail.com>
Date:   Mon Jul 30 13:34:35 2018 +0200

    Initial commit
git checkout 24c1ad

Digression - Git

We simply change to which commit HEAD points, to rollback

 git log --graph --decorate --all
* commit 24c1ad70db1890dcc2b3dbaaa5a151adedaec0b9
| Author: Arian van Putten <aeroboy94@gmail.com>
| Date:   Mon Jul 30 13:34:51 2018 +0200
| 
|     Implement feature C
| 
* commit 1e63d01b43dcdab7636f6e49a8c116b42dd7af8f (HEAD)
| Author: Arian van Putten <aeroboy94@gmail.com>
| Date:   Mon Jul 30 13:34:45 2018 +0200
| 
|     Implement feature A
| 
* commit b5deb132c92bb39e99477432b62adea62dcca43c
Author: Arian van Putten <aeroboy94@gmail.com>
Date:   Mon Jul 30 13:34:35 2018 +0200

    Initial commit
git checkout 1e63d0

Digression - Git

What problems does this method solve?

What do we want?

Idea

Lets make package managers work like git!

Eelco Dolstra. The Purely Functional Software Deployment Model. PhD thesis, Faculty of Science, Utrecht, The Netherlands. January 2006. ISBN 90-393-4130-3.

https://nixos.org/~eelco/pubs/phd-thesis.pdf

Idea

Lets make package managers work like git!

PREFIX= sha1(sha1(deps(package)) + sha1(src(package)) + sha1(options(package))

$PREFIX/bin , $PREFIX/lib  $PREFIX/share
instead of:
/usr/bin, /usr/lib/, /usr/share

Nix

  • Package manager
  • Declarative lanuage to describe package builds
  • Isolated build environments
  • Over 10000 packages and counting
  • Mac OS X / Linux / BSD and Soon Windows Subsystem for Linux*
  • Source-based package manager (Like Gentoo)
  • But don’t worry; also has a build cache

DEMO TIME: Installing a package

nix-build ./nixpkgs.nix -A nginx
tree /nix/store/i5h55rj3mhlad1vbp6rlwvacfafycl4p-nginx-1.14.0
sudo /nix/store/i5h55rj3mhlad1vbp6rlwvacfafycl4p-nginx-1.14.0/bin/nginx
curl http://localhost

nix-env

nix-env -f ./nixpkgs.nix -i  -A nginx
sudo nginx
which nginx
tree /home/arian/.nix-profile
nix-env -f ./nixpkgs.nix -i -A hello
tree /home/arian/.nix-profile
nix-env --rollback
hello
nix-env --rollback
nginx

nix-env

Atomic updates and rollbacks

export PATH=/nix/var/nix/profiles/per-user/arian/profile

/nix/var/nix/profiles/per-user/arian
├── profile -> profile-1-link
│   
├── profile-1-link -> /nix/store/7m5fi-user-environment
│   └── bin -> /nix/store/2gk7-nginx-2.0.1/bin
│   
└── profile-2-link -> /nix/store/34hia-user-environment
    └── bin
        ├── hello -> /nix/store/i5h55-hello-1.14.0/bin/hello
        └── nginx ->  /nix/store/2gk7-nginx-2.0.1/bin/nginx

nix-env

Atomic updates and rollbacks

export PATH=/nix/var/nix/profiles/per-user/arian/profile

/nix/var/nix/profiles/per-user/arian
├── profile -> profile-2-link
│   
├── profile-1-link -> /nix/store/7m5fi-user-environment
│   └── bin -> /nix/store/2gk7-nginx-2.0.1/bin
│   
└── profile-2-link -> /nix/store/34hia-user-environment
    └── bin
        ├── hello -> /nix/store/i5h55-hello-1.14.0/bin/hello
        └── nginx ->  /nix/store/2gk7-nginx-2.0.1/bin/nginx

Important takeaways

How does all this Black Magic work?

The Nix Language

The Nix Language in 1 minute

"hello"
1 + 3
./a/path
[ "i" 3 5 ]
{
  a = 5;
  b = "yo";
}
a = 3
b = 4
add = {x, y}:  x + y // {x,y} => x + y in javascript
add { x = a ; y = b}
people = "Domcode";

"Hello ${people}"

import ./domcode.nix
derivation { /* package build instructions */ }

The derivation function

lol =  derivation { name = "lol";  builder = "lol"; system = builtins.currentSystem; }
"${lol}"
"/nix/store/7kv2zhwjiyzlnfn0lv1fcyd0w8xzcd8r-lol"

The derivation function

location =  /nix/store/sha256({ name = sha256("lol"); builder = sha256("lol")}) + name;
         =  /nix/store/7kv2zhwjiyzlnfn0lv1fcyd0w8xzcd8r-lol

An actual derivation

default.nix builder.sh

An actual derivation

default.nix builder.sh

Graphical representation of our Derivation

Evaluated derivation

Evaluated derivation

If I update the source code

If I update the source code

If I update one of the dependencies …

If I update one of the dependencies …

So why a programming language?

let pkgs = import ./nixpkgs.nix
in
pkgs.stdenv.mkDerivation rec {
  name = "jzmq-${version}";
  version = "3.1.0";
  src = fetchFromGitHub {
    owner = "zeromq";
    repo = "jzmq";
    rev = "v${version}";
    sha256 = "1wlzs604mgmqmrgpk4pljx2nrlxzdfi3r8k59qlm90fx8qkqkc63";
  };
  buildInputs = [ pkgs.zeromq3 pkgs.jdk ];

So why a programming language?

How is a derivation built

How is a derivation built

Reliable builds

cd nixpkgs-channels
git log
cat nginx.nix
nix-build  nginx.nix

What do we want?

Build Cache

nix-repl> "${nginx}"
"/nix/store/i5h55rj3mhlad1vbp6rlwvacfafycl4p-nginx-1.14.0"
if file_exists("${pkg}") {
  return;
} else if download("https://cache.nixos.org/${pkg}") {
  return;
} else {
  build(pkg);
}

Build Cache

nix-repl> "${nginx}"
"/nix/store/i5h55rj3mhlad1vbp6rlwvacfafycl4p-nginx-1.14.0"

Build Cache

Continious integration script

# .travis.yml
language: nix
script:
  - nix build . --store s3://company-bucket
after_success:
  - nix copy . --to s3://company-bucket

How about docker?

Just put it in a damn container - Lucas

Docker?

FROM ubuntu:xenial
RUN apt update -y && \
    apt upgrade -y && \
    apt install python3 \
                python3-pip \ 
                mysql-client \
                liblapack-dev && \
    pip3 install scipy \
                 Flask \
                 sqlalchemy
COPY . /app
WORKDIR /app
ENTRYPOINT ["python3"]
EXPOSE 8080
CMD ["app.py"]
  • Atomic
  • Isolated
  • But reliable?
    • Does xenial still exist?
    • What version packages do I get if I run “upgrade?”
    • What libs are installed by default on xenial?

Challenge

  • Can you take a random commit + Dockerfile from 5 years ago at your company and build your project?

Solution? Docker

  • Docker is an ubiquitos distribution format.
  • Once it builds.. send it to the registry
  • Solves the “runs on my machine” problem
  • Does not solve the “builds on my machine” problem

Best of both worlds

  • Nix has support for building docker containers
  • Copies your package + all its dependencies in a docker image
  • Bare image, no FROM blah
  • Super small
  • You can easily integrate Nix in existing docker-compose or Kubernetes projects!

NixOS - A configuration management tool

Problems with existing tools like Chef / Ansible / Puppet

NixOS - A configuration management tool

Anecdote 1

NixOS - A configuration management tool

Anecdote 2

- name: "enable and start nginx"
  service:
    name: "nginx"
    enabled: true
    state: "started"

NixOS - A configuration management tool

  • Immutable OS
  • Delete some config => different hash => Different package
  • Atomic upgrades and rollback (Your OS is just another Nix package!)
  • INFRASTRUCTURE AS CODE. TRULY

NixOS - A Configuration management tool

NixOps - infrastructure management tool

Downsides of Nix

Recap

Thanks! Questions?

Bonus: Hey did that nginx thingy compile?