Skip to content

Instantly share code, notes, and snippets.

@yihuang
Last active January 6, 2023 15:33
Show Gist options
  • Save yihuang/2b99c80d9df14f75318ef86ebc6158b2 to your computer and use it in GitHub Desktop.
Save yihuang/2b99c80d9df14f75318ef86ebc6158b2 to your computer and use it in GitHub Desktop.
nix tutorial

nix introduction

nix-env: the package manager

$ nix-env -i hello
installing 'hello-2.10'
these paths will be fetched (0.02 MiB download, 0.07 MiB unpacked):
  /nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10
copying path '/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10' from 'https://cache.nixos.org'...
building '/nix/store/lvmi85vn4kgp1f99rhqzc18jxnw4vffn-user-environment.drv'...
created 212 symlinks in user environment
$ which hello
/Users/huangyi/.nix-profile/bin/hello
$ nix-env -e hello
uninstalling 'hello-2.10'
$ which hello
hello not found
$ nix-env --rollback
switching from generation 30 to 29
$ which hello
/Users/huangyi/.nix-profile/bin/hello

Notice:

  • hash in directory name
  • binary package download
  • what is the user-environment
  • uninstalling software is extremely fast

nix-store: an immutable package graph

$ readlink $HOME/.nix-profile/bin/hello
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10/bin/hello
$ otool -L $HOME/.nix-profile/bin/hello
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10/bin/hello:
	/nix/store/c0cbqklqg1ahap52ixv3gwcnmxpwk9f7-Libsystem-osx-10.12.6/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)

Notice:

  • packages are immutable, and connected with absolute paths, thus reproducible.
  • the version number is for informational purposes only, since different versions are already identified by different hashes.
  • a set of packages forms a directed immutable hash graph
    • Can there be cycles?

User environment

A forest of symbolic links:

User environments

Resemblance to git

  • git gc -> nix-collect-garbage

    when the packages finally get uninstalled

  • git push -> nix-copy-closure

    poor man's deployment tool

nixpkgs: the giant package repo

https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/all-packages.nix

How do you maintain such a giant immutable graph?

  • nix expression language

nix-store: query the dependencies

Immediate dependencies

$ nix-store -q --references `which hello`
/nix/store/c0cbqklqg1ahap52ixv3gwcnmxpwk9f7-Libsystem-osx-10.12.6
/nix/store/4yfhzgb68xj7157b9qxxl8gr3v5q5nax-swift-corefoundation

The whole closure

$ nix-store -qR `which hello`
/nix/store/c0cbqklqg1ahap52ixv3gwcnmxpwk9f7-Libsystem-osx-10.12.6
/nix/store/0scgf1j9wdakk4jwplnyrhw8m05vldax-openssl-1.1.1h
/nix/store/84507pkw9i7j3hc2dnc6nrzf10szmbzr-libc++abi-7.1.0
/nix/store/acbsjshd9mpq3hn9i1mj1l03jmc41828-libc++-7.1.0
/nix/store/91c1njy0cx0f02kp4lb571vrwi1n9dgn-ICU-osx-10.10.5
/nix/store/nxffklb14g8yb61p2fv3fpl9sj1mqj1y-zlib-1.2.11
/nix/store/mr5g67r8cnvfrsvsnh22vb82mw9hjqw7-libxml2-2.9.10
/nix/store/7kzamk0abm530kkr5v106hnc3cfscwkc-bash-4.4-p23
/nix/store/7z3yawqmw7haixbkw2kq85k3qjsmrzp5-libkrb5-1.18
/nix/store/8nwp8kh7bzw2h9wmyin8hshibvsq8lwp-libssh2-1.9.0
/nix/store/dpnp2kjxr2hiac1vipvnwc1liwfg8w6x-nghttp2-1.41.0-lib
/nix/store/sk20l6znqrq7rm2mgpxkn0rpfypih70f-curl-7.73.0
/nix/store/4yfhzgb68xj7157b9qxxl8gr3v5q5nax-swift-corefoundation
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10
  • nix-copy-closure basically sync the closure to a remote machine.
  • you can also use nix-store --export nix-store --import together with closure.

Derivation

Derivation is basically nix's terminology for package, it contains all the information needed to build the output of a package. The hash of output is calculated based on the derivation, so the output hash is decided before actual building.

$ nix-instantiate '<nixpkgs>' -A hello
/nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
$ nix-build -Q /nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
/nix/store/mmlnjqg7gbr4w7xjlwj614z97kk1rvfv-hello-2.10
$ nix show-derivation /nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
...

How the output hash get computed

  • Replace the output hash with empty string in the hello.drv file

  • TMP=$(nix-hash --type sha256 --flat hello.drv)
    echo -n "output:out:sha256:$TMP:/nix/store:hello" > tmp
    nix-hash --type sha256 --truncate --base32 --flat tmp
$ nix show-derivation /nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv
{
  "/nix/store/fz4sqv90q68ys3i9sfm2jv8xdzc177wr-hello-2.10.drv": {
    "platform": "x86_64-darwin",
    "builder": "/nix/store/7kzamk0abm530kkr5v106hnc3cfscwkc-bash-4.4-p23/bin/bash",
    "args": [
      "-e",
      "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"
    ],
    "env": {
      "src": "/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz",
      ...
    },
    ...
  }
}

Nix expression language

You use nix expression language to build a derivation, the language has:

  • JSON-like syntax and data structures

    (primitives, record, array)

  • Functional programming

    (higher order functions, closures)

    captured environment in nix code get translated to dependencies of derivation

  • Pure and lazy

    (recursive data structure, fixed point)

Case study

https://github.com/crypto-com/chain-main/blob/master/default.nix

https://github.com/crypto-com/chain-main/blob/master/docker.nix

https://github.com/yihuang/chain-main/blob/testnet/default.nix#L107

Case study - web app

  • Write configuration file

    tasks-ini = writeTextDir "etc/supervisord.conf" (lib.generators.toINI { } {
      "fcgi-program:webapi" = {
        socket = "tcp://0.0.0.0:8000";
        command = "${pyenv}/bin/uvicorn --fd 0 app:app";
      };
      "program:redis" = {
        command = ''${redis}/bin/redis-server
          --port ${toString redisport}
          --appendonly yes'';
      };
      ...
    };
    
  • Combine them into a env

    buildEnv {
      name = "awesome-env";
      pathsToLink = ["/bin" "/etc" "/share"];
      paths = [
        redis
        postgresql
        supervisord
        tasks-ini
      ];
    }
    $ nix-env -i ...
    $ supervisord -c ~/.nix-profile/etc/supervisord.conf

Nix awesome list

https://github.com/nix-community/awesome-nix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment