This is a quick note on a mechanism I came up with to declaratively deploy a python systemd service and its dependencies on NixOS.
I wrote a quick service to serve kea leases as json over http. This is for future work in hardware discovery and provisioning.
I wanted this to run in systemd, using only configuration.nix
to deploy it and its python packages (flask).
I came up with the following:
A unit to clone or pull the repo on boot:
systemd.services = {
clone-kea-lease-server = {
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "kea-lease-server.service" ];
serviceConfig.Type = "simple";
script = ''
if [ ! -d /var/run/kea-lease-server ]; then
${pkgs.git}/bin/git clone https://github.com/nihr43/kea-lease-server.git /var/run/kea-lease-server
else
${pkgs.git}/bin/git -C /var/run/kea-lease-server pull
fi
'';
};
};
and a unit that is the service itself:
systemd.services = {
kea-lease-server = {
after = [ "clone-kea-lease-server.service" ];
wants = [ "clone-kea-lease-server.service" ];
wantedBy = [ "default.target" ];
serviceConfig.Type = "simple";
environment = { NIX_PATH = "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos"; };
script = ''
cd /var/run/kea-lease-server/
${pkgs.nix}/bin/nix-shell . --run 'python main.py --host 172.30.190.1'
'';
};
};
Since we’re using nix-shell
, dependencies in the project’s default.nix
automatically populate at runtime. They’ll be cache in the nix store as well, so this isn’t too terribly wasteful.
Here it all is running:
systemctl status clone-kea-lease-server.service
○ clone-kea-lease-server.service
Loaded: loaded (/etc/systemd/system/clone-kea-lease-server.service; enabled; preset: ignored)
Active: inactive (dead) since Tue 2024-12-17 23:45:59 UTC; 9min ago
Duration: 10.351s
Invocation: 3eb59b246bde448bbd3f5ced9d728155
Process: 39491 ExecStart=/nix/store/c73djiiml5inyyzb7gh12bpmn0ffq6qv-unit-script-clone-kea-lease-server-start/bin/clone-kea-lease-server-start (code=exited, status=0/SUCCESS)
Main PID: 39491 (code=exited, status=0/SUCCESS)
IP: 6.3K in, 2.6K out
IO: 0B read, 0B written
Mem peak: 5.8M
CPU: 140ms
systemctl status kea-lease-server.service
● kea-lease-server.service
Loaded: loaded (/etc/systemd/system/kea-lease-server.service; enabled; preset: ignored)
Active: active (running) since Tue 2024-12-17 23:45:48 UTC; 10min ago
Invocation: bc8350a46df94d2fa6a89466db83232d
Main PID: 39492 (kea-lease-serve)
IP: 27.8K in, 24.5K out
IO: 0B read, 232K written
Tasks: 5 (limit: 19129)
Memory: 45.6M (peak: 286.4M)
CPU: 13.571s
CGroup: /system.slice/kea-lease-server.service
├─39492 /nix/store/p6k7xp1lsfmbdd731mlglrdj2d66mr82-bash-5.2p37/bin/bash /nix/store/1w8ddaz1ax15241j9a7nwkcib1c6q4bf-unit-script-kea-lease-server-start/bin/kea-lease-server-start
├─39493 bash /tmp/nix-shell-39493-0/rc
├─39519 python main.py --host 172.30.190.1
└─39520 /nix/store/zv1kaq7f1q20x62kbjv6pfjygw5jmwl6-python3-3.12.7/bin/python main.py --host 172.30.190.1
Yeah its all running as root. I’ll get around to changing it to the kea user at some point.
Seperating this into two units allows me to restart the service without messing with github, or to trigger just a new clone by restarting the clone- service.