A pod-native stand-in for systemd, for software that expects to run under it.
Some vendor software ships as a systemd-booted image: a Debian userland with /sbin/init as PID 1 and a dozen units that notify readiness, ping a watchdog, and expect pre-start hooks to have run.
Splitting that into one container per service means each container needs whatever systemd did for its unit.
notsystemd is that: run as a container's entrypoint, it reads the vendor's own .service file and runs it the way systemd would, so the image definition is the unit file and nothing more.
$ notsystemd run /lib/systemd/system/unifi-core.servicenotsystemd run [--drop-in-dir DIR]... UNIT_FILEruns a service unit until it exits or notsystemd gets SIGTERM or SIGINT. SIGHUP runsExecReload=. It exits with the service's status.notsystemd is-active UNITexits 0 while the unit is active, for a readiness probe.notsystemd show UNITprints the unit's recorded state as JSON.notsystemd notify [--ready] [--status TEXT] [KEY=VALUE]...sends a notification to$NOTIFY_SOCKET, likesystemd-notify.notsystemd sudo,systemctl,systemd-runandtimedatectlstand in for those commands; see Shims.
Every command takes --state-dir (default /run/notsystemd).
run writes <state-dir>/<unit>.json on every state change, with the unit's ActiveState, SubState, StatusText, MainPID, result and its own PID, and puts the notify socket beside it.
Mount the directory as an emptyDir shared by the pod's containers and each can read the others' state.
Type=simple,exec,notify,forking(with or withoutPIDFile=) andoneshot(withRemainAfterExit=).notify-reloadruns asnotify;dbusandidlerun assimple.ExecStartPre=,ExecStart=,ExecStartPost=,ExecReload=,ExecStop=andExecStopPost=, with the-,+,!,:and@prefixes, quoting,;-separated command lists, and$VAR/${VAR}expansion.ExecStop=andExecStopPost=seeMAINPID,SERVICE_RESULT,EXIT_CODEandEXIT_STATUS.User=,Group=,WorkingDirectory=(including-and~),UMask=andPermissionsStartOnly=.Environment=andEnvironmentFile=(including-), layered over the container's own environment.RuntimeDirectory=,StateDirectory=,CacheDirectory=,LogsDirectory=,ConfigurationDirectory=and their*Mode=, created and owned by the unit's user; the runtime directory is removed on stop.$NOTIFY_SOCKETwithREADY=1,STATUS=,MAINPID=,RELOADING=1,STOPPING=1,WATCHDOG=1,WATCHDOG=triggerandWATCHDOG_USEC=, accepted from any process (NotifyAccess=all).WatchdogSec=andWatchdogSignal=: a missed ping signals the main process and fails the unit.TimeoutStartSec=,TimeoutStopSec=,TimeoutSec=,KillMode=andKillSignal=, escalating toSIGKILLwhen a stop times out.SuccessExitStatus=, with exit statuses and signal names.LimitNOFILE=, set on notsystemd itself so every command the unit runs inherits it, and lowered to what the kernel allows as systemd does.- Drop-ins from
<unit>.d/*.confand from--drop-in-dir, and the%n,%N,%p,%i,%t,%S,%C,%Land%Especifiers.
As PID 1 it reaps every orphan in the container, and treats the whole container as the unit's control group when stopping it. Anywhere else it makes itself a child subreaper, so a daemon that double-forks stays visible.
Restart= is not implemented on purpose: the container exits with the service and Kubernetes restarts it.
Dependencies between units (After=, Requires=, Wants=) are the pod's business too.
The software notsystemd exists for does more than get started by systemd: it runs systemctl, timedatectl and systemd-run, through sudo.
Invoked under one of those names, notsystemd answers as that command, so an image links them to it; the flake's shims package holds the links.
The shims find unit state in $NOTSYSTEMD_STATE_DIR, default /run/notsystemd.
systemctlanswersis-active,is-failed,is-enabled,show(with-p/--propertyand--value),statusandis-system-runningfrom the state directory. A unit the pod does not run reads as inactive, not enabled, andLoadState=not-found.stop,restartand their variants send the unit's notsystemdSIGTERM, so its container exits and Kubernetes starts it again;reloadsends itSIGHUP, andkillsignals the main process. Signalling a unit in another container needsshareProcessNamespace: trueon the pod.start,enable,disable,mask,unmask,daemon-reloadandreset-failedsucceed without doing anything, since the pod spec decides which units run.timedatectlreports NTP as enabled and synchronised, because a container's clock is the node's, and acceptsset-*without changing anything.systemd-runruns its command in place, as--uid/--gidwith--setenv, waiting for it under--waitor--pipeand starting it in the background otherwise.sudoruns its command as-u/-g, keeping the environment apart fromHOME,USERandLOGNAME, and asks for no password. Only root can switch users, as with sudo's-n.
A D-Bus facade serving org.freedesktop.systemd1 from the state directory, for software that watches units' ActiveState and StatusText over the system bus.
nix develop (or direnv) provides Go, ginkgo and gomod2nix.
make test # go tool ginkgo run -r
make build # nix build .#, which also runs the specs
make check # nix flake check
make tidy # go mod tidy, then regenerate nix/gomod2nix.toml