← Back to context

Comment by Arnavion

7 days ago

I dabbled with NixOS many years ago for a much shorter time than the author has spent on it, so I have much less experience with it. My main problem with it was that the problem of declarative config is basically solved at the software-level already.

System services have always been able to be configured by dropping files in /etc. Lots of software also specifically supports config dropins, so that merging configs from multiple sources is even easier. Even stuff like creating users and groups can be done on systemd distros by dropping in config files. Similarly configuring user software is mostly about dropping files in ~/.config etc.

Package managers vary. Alpine's apk is the best in that `/etc/apk/world` is the list of packages you want, and every run of `apk upgrade` will install and uninstall packages accordingly to match that list, but it doesn't have dropins. apt and zypper don't even have a config file, only an opaque database that you can only interact with using the commands. But you can maintain your own packages list and then script apt/zypper to diff against that list and install/uninstall accordingly. (zypper in particular does maintain a list of packages, except it's a list of packages that you *don't* install explicitly but are just auto-installed as dependencies of the ones that you did, which is funny to me.)

I get declarative config on all my devices (a mix of OpenSUSE, Debian, Ubuntu and postmarketOS, across servers, desktops, laptop, phone) with just an Ansible-like setup. For each device I have a `$hostname.roles` file that contains one role per line. Each role corresponds to a `role.$role` directory that contains any files that should be deployed as part of that role (both under homedir as well as at the system level) as well as a `packages` file that lists any packages that should be installed for that role. Then there's a small shell script that matches the hostname of the machine against this directory and ensures that all files exist, and that all the required packages are installed and no extras are installed. Also the entire directory is in version control so I have a log and reasoning recorded for every change.

The author mentions rebuilding a laptop to do another laptop's job by applying the other's Nix config. I have also used my script to rebuild a few devices after their disks died and I had to reinstall the OS from scratch, so it ticks that checkbox too. And of course I've added and removed roles occasionally to add/remove features from individual devices.

NixOS would give me a way to rollback the entire config, but I can also do that with this. In case I need to rollback to packages that no longer exist in the distro repository, I have btrfs snapshots to roll back to.

NixOS would give me a way to install multiple versions of packages, but this is something I've never needed. I primarily stick with distro software so it is always consistent, and if two distro softwares require different versions of the same dependency, distros already know how to solve that (make two coinstallable packages).

The one time I tried to build someone else's Nix project (and they even had a Dockerfile with nix in it to do the build so it would be completely independent of the host), it didn't build for me, so I'm not sure how reproducible it really is. But that might've just been a problem for that one project.

I'm sure Nix(OS) has benefits for other people, but for me the benefits that I would care about are handled entirely by dropping files in the right places, and I don't have to use a different OS or package manager or bespoke programming language to do that.

> an Ansible-like setup

Using another common tool (salt/chef/puppet/...) or something home-rolled? (Just asking because I'm interested in new options in this space)

  • As I said, a small shell script I wrote. The only things it needs to do are sync files according to the `filelist` files and sync packages according to the `packages` files, so I don't need the full verbose DSL of Ansible etc.

    Also it means it has no dependencies on the target machine. You might say Ansible doesn't need anything on the target machine except ssh, but it does require the target machine to be reachable over ssh, which is not necessarily the case if I'm rebuilding a machine such that its network is not already configured. So in that case all I need to do is sneakernet my git repository over and then execute a shell script.

    • How do you deal with removing a package? For examplet the case where you have htop in your config, but no longer want it on your system or in your configs.

      1 reply →