Now Reading
An outline of Nix in follow — skip’s weblog

An outline of Nix in follow — skip’s weblog

2023-11-11 23:54:06



<skip> i’d actually respect it if somebody who is aware of nix might assist tho
🥺
<skip> i requested in nix server and a number of folks have been
like “yea this needs to be working however it doesn’t”
<skip> perhaps i ought to
submit on the discourse hm
<skip> i’ve
misplaced sleep over this lol

— July 25, 2021

I used to be launched to Nix in late 2021 by a pal in a Discord channel, however it
wasn’t my first encounter with the working system/bundle
supervisor/configuration system/programming language hodgepodge.

As a Linux-obsessed baby who continually hopped between distributions, it
inevitably registered on my radar. I used to be all the time on the lookout for the following ISO file to
victimize and duplicate onto my drained USB stick, which might most likely suffocate me in
my sleep if it grew arms. However NixOS was by no means a type of distros. It seemed
too bizarre to my 14-year-old mind.

I nonetheless imagine this. NixOS, and Nix basically, is actually bizarre. I’ve
described it as what finally ends up writhing out of a malfunctioning industrial mixer
that somebody unintentionally dropped Haskell and Bash into. Once I, like many different
pc programmers, inform my associates who don’t write code that “it’s a miracle
that fashionable expertise even works”, Nix is a type of issues that I’m
referring to.

Regardless of this, NixOS is the one distro I set up on my servers. I’m dual-booting
it on my MacBook1. I construct and arrange the event environments for all of
my initiatives with Nix. I exploit Nix to arrange my dotfiles and handle my shell
configuration and private set of put in packages. Nix makes it unflinchingly
easy to duplicate my cozy person setting wherever Nix is accessible, so I can
really feel at dwelling regardless of the place I’m. Nix even turned constructing ffmpeg right into a
cakewalk for that one time I wanted
better AAC encoding2.

Nix is a extremely neat (in my view), however the studying “curve” is akin to
climbing a brick wall with nothing however your fingernails, dedication, and the
extremely skinny shred that’s your remaining persistence. I’m nonetheless not nice at
Nix, and I’m terrified to submit something to the official bundle assortment,
however I hope to demystify it and emphasize what makes it so dang helpful.

Backstage

“Nix”, typically talking, refers to all or any of this stuff:

  1. A ~purely useful programming language with immutability, laziness, floaty
    Haskellesque syntax, and a few attention-grabbing design decisions to make
    configuration and configuration-adjacent duties notably simple.
  2. A bundle supervisor and construct system with the first purpose of reproducibility
    that consumes bundle definitions and construct directions written within the Nix
    programming language.
  3. An enormous repository that homes greater than 80,000 Nix bundle definitions
    written and maintained by over 5,000 contributors, referred to as “nixpkgs”.
  4. A Linux distribution (“NixOS”) that makes use of Nix3 to declaratively specify the
    whole configuration of the system, akin to: which packages are to be
    put in, which person accounts exist on the system, and what companies are
    lively.

All of those puzzle items match collectively to create one thing that’s actually distinctive
and terrifying. Hooray!

Nix is completely different from different bundle managers in that it’s actually and totally
obsessive about making issues solely self-contained. When Nix builds a bundle,
the construct setting is remoted such that nothing outdoors of what you declare
is accessible. Having globally put in libraries which are acknowledged by
configure scripts, CMake, and so forth. generally is a large ache, particularly whenever you want
a selected model or end up needing to use bespoke patches. Generally
the precise model of a library you require simply isn’t out there simply. Having
a number of variations put in will be both tough or nigh unimaginable.

Nix avoids this by having binaries reference their dependencies explicitly.
Checklist the shared libraries wanted by a binary that was constructed by Nix, and also you’ll
see one thing like this:

$ ldd "$(which curl)"
	linux-vdso.so.1 (0x00007fffeeb86000)
	libcurl.so.4 => /nix/retailer/rirzp6ijbcwnxlf0b2n286n587r3z9jw-curl-7.86.0/lib/libcurl.so.4 (0x00007ffb5ce40000)
	libssl.so.3 => /nix/retailer/4mxnw95jcm5a27qk60z7yc0gvxp42b9a-openssl-3.0.7/lib/libssl.so.3 (0x00007ffb5cd93000)
	libcrypto.so.3 => /nix/retailer/4mxnw95jcm5a27qk60z7yc0gvxp42b9a-openssl-3.0.7/lib/libcrypto.so.3 (0x00007ffb5c914000)
	libz.so.1 => /nix/retailer/026hln0aq1hyshaxsdvhg0kmcm6yf45r-zlib-1.2.13/lib/libz.so.1 (0x00007ffb5c8f6000)
	libc.so.6 => /nix/retailer/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libc.so.6 (0x00007ffb5c6ed000)
	libnghttp2.so.14 => /nix/retailer/qz400bwshaqikj5s2qyvh0c9qffgmqik-nghttp2-1.49.0-lib/lib/libnghttp2.so.14 (0x00007ffb5c6bc000)
	libidn2.so.0 => /nix/retailer/5mh5019jigj0k14rdnjam1xwk5avn1id-libidn2-2.3.2/lib/libidn2.so.0 (0x00007ffb5c69a000)
	libssh2.so.1 => /nix/retailer/vqq9s0d6fw6kqf3sr5nrzqbys9rhygqd-libssh2-1.10.0/lib/libssh2.so.1 (0x00007ffb5c659000)
	libgssapi_krb5.so.2 => /nix/retailer/r7gl900my2fw6k33nxh2r7rzv8nv0s25-libkrb5-1.20/lib/libgssapi_krb5.so.2 (0x00007ffb5c606000)
	libzstd.so.1 => /nix/retailer/w10in9diaqrcqqxi5lg20n3q2jfpk6pq-zstd-1.5.2/lib/libzstd.so.1 (0x00007ffb5c540000)
	libbrotlidec.so.1 => /nix/retailer/9iy1ng7h1l6jdmjk157jra8n4hkrfdj1-brotli-1.0.9-lib/lib/libbrotlidec.so.1 (0x00007ffb5c532000)
	libdl.so.2 => /nix/retailer/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libdl.so.2 (0x00007ffb5c52d000)
	libpthread.so.0 => /nix/retailer/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libpthread.so.0 (0x00007ffb5c528000)
	/nix/retailer/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/ld-linux-x86-64.so.2 => /nix/retailer/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib64/ld-linux-x86-64.so.2 (0x00007ffb5cee7000)
	libunistring.so.2 => /nix/retailer/34xlpp3j3vy7ksn09zh44f1c04w77khf-libunistring-1.0/lib/libunistring.so.2 (0x00007ffb5c37a000)
	libkrb5.so.3 => /nix/retailer/r7gl900my2fw6k33nxh2r7rzv8nv0s25-libkrb5-1.20/lib/libkrb5.so.3 (0x00007ffb5c29f000)
	libk5crypto.so.3 => /nix/retailer/r7gl900my2fw6k33nxh2r7rzv8nv0s25-libkrb5-1.20/lib/libk5crypto.so.3 (0x00007ffb5c270000)
	libcom_err.so.3 => /nix/retailer/r7gl900my2fw6k33nxh2r7rzv8nv0s25-libkrb5-1.20/lib/libcom_err.so.3 (0x00007ffb5c26a000)
	libkrb5support.so.0 => /nix/retailer/r7gl900my2fw6k33nxh2r7rzv8nv0s25-libkrb5-1.20/lib/libkrb5support.so.0 (0x00007ffb5c25a000)
	libkeyutils.so.1 => /nix/retailer/816qwr4xy058451rbxr0ccyh1v1akhb6-keyutils-1.6.3-lib/lib/libkeyutils.so.1 (0x00007ffb5c251000)
	libresolv.so.2 => /nix/retailer/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libresolv.so.2 (0x00007ffb5c23f000)
	libm.so.6 => /nix/retailer/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libm.so.6 (0x00007ffb5c15f000)
	libbrotlicommon.so.1 => /nix/retailer/9iy1ng7h1l6jdmjk157jra8n4hkrfdj1-brotli-1.0.9-lib/lib/libbrotlicommon.so.1 (0x00007ffb5c13c000)

Assuming that the bundle is constructed accurately and also you aren’t enjoying any runtime
linker tips in your finish, it’s just about unimaginable to run into library errors.
Having a number of variations of a library put in is a nonissue, and dependency
hell falls into irrelevancy.

Binaries are vacuum packed in that they solely ever refer to precisely what they
want, and this is applicable for each runtime and construct dependencies alike.

As a result of the Nix retailer is actually an append-only graph database4 with
nodes being packages and edges being dependency relations, I may even question it
to see e.g. ffmpeg’s runtime dependencies, each direct and oblique:

An end-to-end graph of ffmpeg's dependencies.

Dropped at you by nix-store and graphviz.

On the high, we see CoreFoundation, which is a core macOS system framework that
a number of packages depend upon. We will additionally spot dejavu-fonts-minimal, which is
wanted by fontconfig, which is required by libass to render subtitles, which
is required by this default configuration of ffmpeg. Emphasis on default: we are able to
override choices supplied by the bundle definition and specify .patch recordsdata
to be utilized to the supply code.

To maximise reproducibility, Nix works on the supply code of a bundle. However
as a result of each bundle is inbuilt its personal universe, this can be very cacheable.
Nix bundle installations are capital F Quick, as a result of there’s no dependency
decision to be completed. It quantities to downloading knowledge from a CDN and unpacking
it, and it may possibly’t get any sooner than that.

Executing “over 350,000 builds every week”, the NixOS basis maintains
a massive Nix build farm for x86-64 and aarch64 Linux and macOS,
importing the construct artifacts to
a widely-available binary cache.

As Nix evaluates the construct directions domestically, it hashes the consequence and
queries the cache for it. In concept5, between techniques of the identical platform,
there’s no distinction between constructing the specified bundle and copying the
outcomes from the cache. Taking an excessive quantity of care to isolate builds from
each other makes this sensible.

Which means in strange circumstances, you gained’t need to construct packages from
scratch. In case you impose an override onto a bundle that adjustments the ensuing
construct directions, Nix doesn’t discover a cached consequence from the cache as a result of
differing hashes, and the bundle is constructed domestically.

Nix’s method to builds additionally has another neat results:

  1. Cross-compilation becomes easier,
    which sadly complicates the general infrastructure however makes
    approaching this drawback comparatively much less scary…most likely.
  2. Remote build
    assist permits you to consider a bundle’s (probably personalized) construct
    directions in your native field, then ship them to a extra highly effective machine
    over the community to construct. This isn’t solely cool, but in addition vital ought to
    the bundle not be supported in your native platform. Distributed builds, CI,
    et cetera! The sky is the restrict.
  3. nix-copy-closure
    copies the outcomes of a construct and its whole runtime dependency tree (referred to as a
    “closure”) between machines of the identical platform, avoiding pointless work.
  4. Cache your individual stuff!
    Host your own binary cache, or use a
    service like Cachix to keep away from rebuilding.

Ephemerality

xkcd 1987

This sums it up, I feel.

Managing Python environments just isn’t solely painful, however actively damaging to the
psyche.

Establishing an ephemeral Python setting with OpenCV will be completed in Nix like
so:

$ nix-shell --pure -p "python3.withPackages(packages: [ packages.opencv4 ])" --run python3
Python 3.10.10 (major, Feb 17 2023, 05:25:10) [Clang 11.1.0 ] on darwin
Sort "assist", "copyright", "credit" or "license" for extra data.
>>> import cv2
>>>

I can run the same command to drop myself right into a REPL with NumPy or SciPy, or
any bundle basically: a sure model of Java, or perhaps a Node or Haskell
setting.

Dissecting the command:

  1. The --pure flag clears the setting earlier than dropping you into the shell,
    stopping e.g. $PATH from leaking via.

  2. -p specifies which bundle(s) we’re keen on. On this case, python3
    (which presently resolves to python310 on the 22.11 channel). We use
    withPackages to point that we’d wish to create an setting with the
    opencv4 Python bundle out there.

    python3.withPackages(packages: [ packages.opencv4 ])
    

    That is Nix code that makes use of bundle definitions from nixpkgs, which has
    particular infrastructure for Python, Python packages, and managing Python
    environments. Nix has related infrastructure for Rust, Node.js, and so forth.

  3. --run drops us immediately into the Python REPL as an alternative of Bash.

Invoking this command causes Nix to compute which packages is required and what
Python setting trickery must be completed. If the required packages aren’t
in my Nix retailer already, they’re downloaded from the binary cache. Once I exit
the shell, my native Python person setting stays fully untouched. The
basic nature of Nix permits this to occur in a frictionless approach—no
virtualenv futzing required.

Nix’s modular nature permits it to cooperate with different applied sciences, too. Take
Docker, as an example:
Nix is seemingly better at generating smaller images;
as a result of
it knows everything about every package,
it may possibly purge superfluous knowledge all the way down to the nanometer and hold solely the bits that
matter.

Declarative techniques

NixOS takes wacky declarative bundle administration to its subsequent logical conclusion
by utilizing the identical expertise to find out to service topology of your Linux
system. In essence, your system configuration turns into a bundle that’s managed
and put in by Nix identical to every other.

That is what a minimal NixOS configuration appears to be like like (in follow, actual
configurations are a lot bigger):

{ config, pkgs, ... }: {
  imports = [
    # Import another Nix module that contains the results of the hardware scan.
    # (Includes important kernel modules for hardware, the filesystem table, etc.)
    ./hardware-configuration.nix
  ];

  # Allow a bootloader for UEFI techniques.
  boot.loader.systemd-boot.allow = true;

  # Allow the OpenSSH server.
  companies.sshd.allow = true;

  # Add some helpful packages for everybody.
  setting.systemPackages = with pkgs; [ git curl wget ];

  # ...
}

As somebody with ADHD and comparatively poor reminiscence retention, NixOS is a godsend
for managing my fleet of servers. After not having logged right into a field for a
whereas, I simply overlook what companies exist on the server. I’m too lazy to
keep this in writing, however it’s OK as a result of Nix permits declarative administration
of those companies. It acts because the definitive supply of fact.

Determining precisely what a server does with out worry of documentation
desynchronizing with what truly exists on the server is a single
$EDITOR /and so forth/nixos/configuration.nix away.

NixOS differs from one thing like Ansible in that it’s inherently declarative,
via and thru. In case you take away the companies.sshd.allow = true; line from
your configuration, NixOS will tear down the OpenSSH server upon a rebuild.
It’ll be as if it was by no means there (subtracting any leftover knowledge), as a result of there
isn’t a sensible distinction between putting in NixOS for the primary time and
constructing it once more. Ansible has the notion of “idempotency”, however Nix (and NixOS)
is idempotent by nature.

NixOS isn’t particular:

  1. You’ll be able to construct a NixOS system and duplicate the closure to a different machine to make use of.

  2. You’ll be able to
    make a custom version of the NixOS installer ISO
    together with your desired customizations to craft your ideally suited Linux rescue USB.

  3. You’ll be able to
    test experimental changes to your system
    by sandboxing it inside a QEMU digital machine:

    $ nixos-rebuild build-vm
    
    # Run your new system within a VM to see if one thing broke.
    $ ./consequence/bin/run-*-vm
    
  4. As a result of virtualization is made simple with declarative configurations, NixOS
    maintainers
    test their own code with it.

  5. As a result of Nix packages are totally self-contained,
    previous generations of the system are tracked,
    so you possibly can rollback anytime within the boot menu. I used this as soon as after I
    unintentionally hosed my community configuration and wasn’t positive how you can repair it.

  6. Not solely are earlier generations saved round, system upgrades are
    primarily totally atomic. New model of libc (or different Vital™️
    library)? On an strange system, changing the file with out rebooting would
    most likely summon flesh-eating demons. However with Nix, this isn’t an
    difficulty—each bundle was already referencing the model it relied on
    via an absolute path into the Nix retailer.

Saving disk house is simple, too. Being a function of Nix basically,
the garbage collector
can clear up computed construct directions, previous profile/system generations, and
different construct dependencies that aren’t wanted for a functioning system. This runs
fairly quick and is a pleasant crutch for these instances you simply want extra room.

$ sudo nix-collect-garbage -d
# ...
16730 retailer paths deleted, 11828.97 MiB freed # :O

Declarative, modular techniques

nixpkgs comes with an enormous variety of included modules that port different software program
and companies to be usable with NixOS.

One thing that’s genuinely terrifying to set as much as me is GitLab. It simply has
too many shifting components. To deploy it with NixOS, I’ve this in my configuration:

{
  companies.gitlab = let
    secretFile = "/var/lib/gitlab-secret";
    rsaSecretFile = "/var/lib/gitlab-secret-rsa";
    initialRootPasswordFile = "/var/lib/gitlab-initial-root-password";
  in {
    allow = true;
    host = ...;
    port = 80;
    https = true;
    inherit initialRootPasswordFile;
    secrets and techniques = {
      secretFile = secretFile;
      dbFile = secretFile;
      otpFile = secretFile;
      jwsFile = rsaSecretFile;
    };
  };
}

Aside from specifying some paths to recordsdata containing secrets and techniques (a caveat which
I’ll elaborate on later), that is all I would like for a functioning GitLab setup. If
I modify my thoughts on this sooner or later, all I’ve to do is flip
allow = true; to false, or outright evict this code block from my
configuration.

By doing this, all required companies instantly cease and grow to be disabled. If I
run the rubbish collector, all GitLab packages are deleted. All that continues to be is
any person knowledge that was created by the companies in query. That is significantly
superior to me, as a result of GitLab is exemplary of being considerably of a behemoth to
arrange, regardless of Omnibus.

What’s even higher is the inherent advantage of a modular and declarative
configuration. For instance, certainly one of my servers can also be answerable for internet hosting an
authoritative DNS server, which has a corresponding NixOS module in nixpkgs:

{
  companies.nsd = {
    allow = true;
    interfaces = [ "0.0.0.0" ];
    verbosity = 2;
    zones.howl.youngsters = {
      "howl.".knowledge = ''
        $ORIGIN howl.
        $TTL 3600

        @ IN SOA howl. tinyslices@gmail.com. ( 2021122201 28800 7200 864000 60 )
        @ IN NS louie.howl.

        ${lib.concatStringsSep "n" config.howl.information}
      '';
    };
  };
}

An authoritative DNS server vends information as an alternative of merely resolving and
caching them. Right here, I’m directing
nsd (the DNS server in
query) to hear on the unspecified handle6. I’m utilizing it with
Tailscale, which is a extremely neat service that allows
a zero-config mesh VPN between all of my servers and gadgets. (NixOS additionally has a
module for it—simply companies.tailscale.allow = true;.)

Most significantly, I’m defining a customized NixOS choice: howl.information, which lets
me simply add strains to the zone from different modules. That is vital.

{
  choices.howl = with lib; {
    information = mkOption {
      kind = varieties.listOf varieties.str;
      description =
        "Authoritative DNS information uncovered to each machine within the tailnet";
    };
  };
}

Once I write the code to allow the nsd module above, I be certain to reference
the ultimate worth of this tradition choice (as config.howl.information) within the zone
configuration, which is collected from all cases of the choice being
modified in different modules. Nix’s lazy analysis crucially permits this.

Now, in one other NixOS module—say, monitoring.nix, I can allow Grafana and
different companies akin to Prometheus. I may tweak Nginx and inform it to reveal
its standing web page, and likewise create digital hosts for Grafana and Prometheus. And
in the identical breath, I can create DNS information for all of those new companies, so
each machine linked to the tailnet can entry them painlessly:

{ lib, ... }:

let
  inherit (import ./web.nix) localhost inside ports;
in
{
  companies.grafana = {
    allow = true;
    port = ports.grafana;
    area = "grafana.howl";
    rootUrl = "http://grafana.howl";
  };

  companies.prometheus = {
    allow = true;
    port = ports.prometheus.prometheus;
    globalConfig.scrape_interval = "10s";
    scrapeConfigs = [{
      # ...
    }];
    exporters = {
      # ...
      nginx.allow = true;
    };
  };

  # Instruct Nginx to reveal its standing web page for Prometheus.
  companies.nginx.statusPage = true;

  # Configure Nginx vhosts for these new companies.
  companies.nginx.virtualHosts."grafana.howl".areas."/" = inside {
    proxyPass = localhost ports.grafana;
  };
  companies.nginx.virtualHosts."prometheus.howl".areas."/" = inside {
    proxyPass = localhost ports.prometheus.prometheus;
  };

  # Add strains to the DNS zone for these new companies.
  howl.information = [
    "grafana.howl. IN CNAME louie.howl."
    "prometheus.howl. IN CNAME louie.howl."
  ];
}

I import this new module in my major configuration:

{
  # ...
  imports = [
    # ...
    ./monitoring.nix
  ];
}

And after a rebuild, Nix pulls within the required packages and builds the system
closure, enabling and configuring each service that I declared to be lively.

For my part, that is the place NixOS actually shines. I’m in a position to allow and
configure Grafana, Prometheus, Nginx, and the DNS information that need to do with
these companies in a single file. I’m defining shared constants in a separate
place and utilizing them throughout configurations which are written in fully
completely different languages and syntaxes
.

With conventional server administration, I’d have to put in the proper packages,
lookup the paths to their configuration recordsdata, and perhaps even run some instructions
to switch some mutable state. I’ll overlook all of this in a couple of days and even
hours, however Nix lets me authoritatively describe it in code.

If I resolve to cease importing that file in my configuration, then the DNS and
Nginx digital hosts are eliminated; Nginx stops exposing its standing web page;
Prometheus and Grafana’s systemd models are disabled; and all unneeded packages
are not reachable from a rubbish collector root, making them eligible for
deletion.

NixOS lets me unify and modularize what would in any other case be disconnected
configurations throughout packages in a extremely idempotent, cacheable, and
declarative approach, primarily homogenizing each service on the system. That’s
wonderful to me.

Diving in

I’m deliberately avoiding the main points right here as a result of I imagine it’s vital to
first grasp the massive image behind Nix and NixOS, and perceive what it’s actually
helpful for.

I write and keep a couple of Discord bots. To ease the upkeep and deployment
of those critters, I’ve created a base that lets me share the identical improvement
setting and routinely generate a NixOS module for all of them, with
customization and extension factors every time vital. I’m keen on writing
some detailed case research on how I completed this, however this submit is getting
actually lengthy, and we nonetheless aren’t completed!

For now, listed below are some assets that I personally advocate for perusal ought to
you have an interest:

  1. Zero to Nix: New child on the block; mild and
    extra detailed introduction to utilizing Nix in follow.
  2. “Nix: What Even is it Though”,
    a presentation by Burke Libbey.
  3. Nix Pills: Study Nix from the underside
    up.
  4. The
    Nix Reference Manual
  5. nixpkgs manual and
    NixOS manual: The official
    documentation for these initiatives.
  6. nix.dev: An opinionated handbook and “survival information”.
  7. NixOS Search: A useful software for
    rapidly trying up packages and NixOS choices. Maintain this on velocity dial.
  8. noogle eases the trying up of library capabilities.

When docs aren’t wonderful, studying turns into akin to patchwork: you slowly and
incrementally sew squares into your quilt till you attain a sure level
the place the whole lot turns into clear, and you find yourself with one thing good and comfortable to
hold you heat throughout winter.

Rougher edges

Each expertise includes a set of tradeoffs, and Nix isn’t any exception.

One specific ache level is managing secrets and techniques: the Nix retailer is world-readable,
and this contains any configuration recordsdata that will or could not include secret
keys and passwords. This drawback is tackled through initiatives akin to agenix and
others, however hold this in thoughts when blueprinting your system. I’ve experimented
with committing my nixfiles with their encrypted secrets and techniques in public earlier than, however
this ended up being such a large ache that I gave up. Perhaps I’ll attempt once more
quickly.

In the case of libraries and scaffolding your individual initiatives with Nix, it may be
arduous to search out what’s applicable to be used.

Two good examples: packaging Rust code, and deploying NixOS. I used to wield
Naersk to blast my Rust packages with the Nix beam, however was later really useful
Crane by a pal, which appears to require much less ceremony. I by no means would’ve
came upon about it in any other case. nixpkgs additionally appears to have built-in assist for
Rust through buildRustPackage. I’m unsure which one is one of the best to make use of; it’s
unclear to me, however I’ve settled on Crane for now.

A screenshot of a successful colmena command invocation.

Construct and apply your Nix config with a single command.

Deployment to different servers from your individual field is peak consolation. There are a lot of
Nix deployment options, however I’ve settled on Colmena, as a result of it helps
macOS and Flakes. There’s additionally Bento (which tries to maintain it easy), as effectively
as Morph and nixops. And there’s most likely extra I’m lacking. There’s a number of
selection right here.

I run into the same feeling once I write Nix code myself. The documentation
story right here might use some enchancment: discovering the precise operate to make use of can
really feel like navigating a dense jungle with a machete. I really feel like studying different
folks’s Nix code is without doubt one of the best methods to study Nix, since you
get to see how its used (and the way folks resolve their particular issues) in
follow.

GitHub’s code search is an
invaluable software right here, in addition to poking round in nixpkgs and asking questions
in neighborhood channels. Plenty of studying Nix is completed hands-on; you’ll must
throw issues at a wall to see what sticks, and that’s going to be irritating at
first.

The character of Nix

Nix is infectious, which will be each good and dangerous. Having a common,
omnipresent existence in your system is what permits Nix’s niceties, but in addition
could make it irritating to simply do issues.

You’ll be able to’t comply with README directions verbatim anymore: if you wish to use
one thing, it needs to be packaged by Nix. Or, no less than, it ought to. If there
occurs to be a Nix bundle maintained by somebody in nixpkgs, nice! If not, you
higher be in a temper to write down some Nix code.

My dotfiles are Nix-managed, too. Which means my complete person setting is
simply reproducible in every single place Nix is accessible. Nevertheless, which means I would like
to rebuild my person bundle each time I make a change, as a result of the
configurations have to be constructed, copied into the Nix retailer, after which symlinked
into my own residence listing.

Any change I make—massive or small—has to undergo Nix earlier than applications take
discover, which will be annoying.

Fortuitously, you aren’t pressured to undertake Nix to such a excessive diploma. You’ll be able to even
set up it on different Linux distributions, because it’s only a bundle supervisor. By
doing this, you get to choose and select what falls beneath Nix’s reign. The extra
you resolve to make use of, although, the extra you’ll need to zap issues with the Nix ray.

Take black field binaries, for instance: tarballs of pre-built blobs, sans supply
code, that you just “simply” need to unpack and run. Nix inherently doesn’t play effectively
with these, and that may make sure issues more durable to do (see: video games).

If patching the binaries in query is viable, patchelf can come to the
rescue. A pal of mine who’s attempting out NixOS is utilizing it to patch binaries
to be able to run Garry’s Mod servers, that are in a position to interface with exterior
Third-party plugins through dlsym and different runtime loading.

When patching is unfeasible, akin to applications that carry out integrity checking or
merely make too many assumptions concerning the outdoors world,
buildFHSUserEnv lets you run light-weight sandboxes
which are appropriate with the Filesystem Hierarchy Customary (/usr/lib and
associates), made doable via Linux namespaces. That is completed to support
Steam
, which is fairly rattling intelligent.

Steam has all the time felt fairly fragile to me. For instance, it requires its personal
bespoke set of libraries that it downloads and maintains outdoors of the system
bundle supervisor. This sucks, however it’s cool that it was doable for Nix to shove
it right into a reproducible field of types that principally can’t break (let’s hope I
don’t jinx it).

When packaging different software program that we’ve got a diminished quantity of management over,
issues can get a bit of wonky. Once I put in NixOS on my Mac, I bumped into an
difficulty the place ArmCord—a neat little mission that wraps Discord natively for
ARM gadgets—wouldn’t open hyperlinks in my net browser.

After some poking round with Chromium’s logging ranges, I ultimately received it to
spew out sufficient debug data to see why xdg-open (which is what’s being
spawned to open my net browser) was failing:

XPCOMGlueLoad error for file /nix/retailer/5mndwvvbdz07kllj6bs0pp1n82cx260i-firefox-110.0.1/lib/firefox/libxul.so:
/nix/retailer/p9ggv8qkdv0s7pckz2xkxxs68ras07g3-nss-3.79.4/lib/libssl3.so: model `NSS_3.80' not discovered (required by /nix/retailer/5mndwvvbdz07kllj6bs0pp1n82cx260i-firefox-110.0.1/lib/firefox/libxul.so)
Could not load XPCOM.
/dwelling/slice/.nix-profile/bin/xdg-open: line 881: x-www-browser: command not discovered
XPCOMGlueLoad error for file /nix/retailer/5mndwvvbdz07kllj6bs0pp1n82cx260i-firefox-110.0.1/lib/firefox/libxul.so:
/nix/retailer/p9ggv8qkdv0s7pckz2xkxxs68ras07g3-nss-3.79.4/lib/libssl3.so: model `NSS_3.80' not discovered (required by /nix/retailer/5mndwvvbdz07kllj6bs0pp1n82cx260i-firefox-110.0.1/lib/firefox/libxul.so)
Could not load XPCOM.

To my shock, there have been… linking errors occurring! Firefox gave the impression to be
loading the inaccurate model of OpenSSL for some motive. I believed Nix was
presupposed to be reproducible, self-contained, and so forth. and so forth. This shouldn’t be
occurring!

Extra investigation led to the belief that the ArmCord bundle truly
injects LD_LIBRARY_PATH at runtime in order that it may possibly discover the
proper libraries—wanted as a result of the bundle reuses the .deb binaries—and it
was bleeding into the xdg-open subprocess that was being spawned. Whoops.

I used to be in a position to repair this by wrapping xdg-open with a pristine script that unset
LD_LIBRARY_PATH, and overriding the ArmCord package to add a wrapper that
invoked the main binary with the pristine script prepended to PATH before
anything else
. Then, when xdg-open was spawned by Chromium,
LD_LIBRARY_PATH would not be clobbered.

On this scenario, overriding the bundle definition right here was sufficient to resolve my
drawback, however which may not all the time be the case: NixOS modules, and Nix packages
basically, are solely as versatile as they’re written to be7. To date, I’ve
by no means needed to straight-up fork a bundle or NixOS module definition, however I’m
undoubtedly not ruling that out from ever occurring.

Fortunately, there tends to be a number of escape hatches: nixpkgs could be very configurable
and extensible with assist for overlays, overrides, and supply code patches.
It’s additionally completely doable to do one thing akin to making a bundle that
solely takes the output of one other bundle and patches it in a sure complicated
approach (nevertheless you need!)

Lastly, I’d wish to reiterate that as a result of Nix is a lazily evaluated (and
dynamically typed) language, it’s very doable to run into pretty cryptic
errors typically, particularly when recursion is concerned. Lazy analysis signifies that
it’s doable to introduce a ticking time bomb that may be detonated from
seemingly unrelated code.

Whereas this generally is a ache, it’s additionally what permits Nix to keep away from pointless
computation: the foundation of nixpkgs is a large tree of each bundle contained
inside the repository, however solely these which are truly wanted are ever
evaluated. Deferring analysis to the final doable second is what makes issues
akin to overrides and overlays doable.

Backside line

Nix is quirky, distinctive, and a bit of tough across the edges. Debugging it, like a
lot of different issues, is irritating. However the advantages I get from utilizing it
presently outweigh the disadvantages, offering sufficient incentive for me to maintain
on investing in it.

What I discover to be most helpful for me is declarative system administration through NixOS.
My reminiscence span is just about nonexistent these days, and having a technique to declare my
servers fully idempotently is an unbelievable technique to keep away from confusion and
stress. I like having that philosophy prolonged to my private initiatives and person
setting, because it ensures a stage of consistency and reproducibility that I
haven’t discovered wherever else.


Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top