I’d like to continuously deploy some software on a NixOS system with a separate cadence to the system profile. I can’t seem to find much about this, although I’ve seen it referred to in various posts, e.g. Home-manager is a false enlightenment mentions using nix-store --realise and nix-env --set.
I would want to be able to run some command on the server itself, ideally not as the same user that the service runs as, nor root.
Triggering is not a problem, I’d probably use a systemd path unit for this, watching the artefact output directory of the CI runner (laminar).
It seems as though deploy-rs has half the machinery that I want, namely multi-profile support (albeit without an activation function for this approach). I’m wondering what else I would need, or, alternatively, what other (simpler?) options there are, particularly since I don’t need to be able to do this remotely.
I’ve explored this some myself, but there’s no “tool” which provides this for you. At work we use a well known file path and a predefined systemd unit which points to the well know path, and we orchestrate a realize/restart. As far as i’ve found, at this point you’ll have to build it yourself.
I am sure I am missing something, but you can always just call nix-build on any old nix expression and it will happily stick it in the the store, and leave a gc root at whatever path you like, no nix-env required.
I think configuration is the main thing that makes this tricky for me, which I can’t see nix-build or nix-env providing, but I did just think that perhaps I can use makeWrapper to realise the configuration file path and associate it with the correct version. Time to experiment!
What do you need makeWrapper for? Assuming you have a ./foo.conf config file and pkg.nix as some function producing a derivation then you can make a default.nix like
let
pkgs = $pinnedPkgs;
pkg = pkgs.callPackage ./pkg.nix {};
in
pkgs.writeShellScript "service" "exec ${lib.getExe pkg} --conf ./foo.conf"
where $pinnedPkgs is whatever you use to get nixpkgs in scope
then nix-build ./default.nix -o $path will drop an executable at $path that you can execute. I don’t think it takes too much more linux admin imagination to see how to package that into something that can update a service on some some trigger.
I personally find 10x easier to read a straightforwardly assembled shell script. This is also potentially me not understanding makeWrapper, but given that it is a setup hook you would need to do something like
If you want to build it remotely that’s fine, do that, and use nix-copy-closure + nix-store --add-root $stable_path -r $store_path, I haven’t tried exactly that, but I don’t see why it wouldn’t work. You’d just need to watch out for gc.
Given that $WORKSPACE points to a flake with a default output for the current system. I had issues referencing a config files with ${./config}, claiming that /var could not be accessed in restricted mode, which, of course, is where my CI config is. For the first project I’m doing this with, I’ve made the default config work for my deployment, so I don’t need to specify the config file, but of course that’s not always feasible. I know that there’s other ways to do this, so I’m not too concerned.