This is a bit of a rant, a bit of an educational post, and really came about because I'm just tired of how much flak systemd got and still gets based on obscure philosophical "issues". That's not to say I fully disagree, I'm just a pragmatist. I think it's better in a lot of ways. But when someone comes in to defend systemd, what do they usually have to offer? What improvements justify that philosophical sacrifice? "Uh, it boots fast. And BASH is annoying." Cool. Clearly that's convinced some people, but it doesn't really give any compelling reasons for why it's "better".
The documentation for systemd is utter crap, and finding out everything about what it can do involves slogging through pages and pages of boring documentation with no examples. Even those who have been using systemd for years probably have no idea of half of what it can do.
So I'm here to tell you about a couple really cool features that you probably never heard about, that might change your mind about systemd, at least in a practical sense. If they don't, that's fine. But at the very least, if you're stuck with it in every major distro, you can at least know some neat features that might be useful to you!
#1 – Seriously,
service units are great.
This one does come up a lot as a defense, but I'd be remiss not to repeat it. Boilerplate BASH SysV initscripts are crap. They're fragile, they're annoying to read, they're annoying to write, and half the time they're just calling
start-stop-daemon anyways, which is a half-assed service manager at best. Systemd units are clean, concise, and powerful. They're worth a look on their own merits if you've ever written an initscript and hated every moment of it. You can auto-restart failed units, you can delay the restart, you can do actions… so much power, no BASH knowledge necessary.
This is a cool little feature of units. You can specify an
OnFailure entry in your unit to execute another arbitrary unit if the service fails. For example, a
oneshot unit that sends you an email. Or perhaps starting a secondary daemon to do something else. Really anything you want.
ExecPostStart and similar
OK, yea, you can do this in BASH initscripts too, but Systemd just makes it so… accessible. Want to
git pull before starting a service? Want to remove a cache directory on exit? Easy peasey. Add
ExecPreStart = /path/to/myscript to execute
myscript before starting the main
ExecStart. And systemd will fail the whole unit if the
Pre command fails. If you don't want that, you can make them optional as well by adding a
- before the path.
#4 – Mount units
This is a biggie. You may have heard of them in the context of
fstab, how Systemd "destroys" it. But this is incredibly short-sighted. First, editing fstab programmatically (looking at you, Ansible) is a pain in the ass and fraught with dragons. Mount units let you create mount definitions atomically. Second, you can depend anything on them! Imagine you have an NFS filesystem and a Free Software Media server (shameless /r/jellyfin plug). You don't want that server to start if your filesystem isn't mounted, because bad things would happen if you do. What can you do?
mount -a is a hack. No – use a
.mount unit for your NFS volume, and then
Requires = my-mount.mount in the service! Now you're safe.
There is one major caveat though: if you have a
- in your mount directory target, you're going to have a very bad time, since the unit is named
path-to-mountpoint.mount with the
- replacing the filesystem
/ separator, and escaping the dashes almost never works. Otherwise, though, they're incredibly powerful.
Have a unit installed by an operating system package, but you want to do some interesting things to it? The first thing everyone thinks is to just edit the
/lib/systemd/system/my-unit.service file and go wild. But, this will be overwritten on an upgrade. OK, you might read a bit, and then copy it from
/etc. That won't be overwritten. But now you've duplicated the unit, and won't get nice improvements from your packages. The solution?
/etc/systemd/system/my-unit.service.d/! Using this directory, you can override small components of the unit file with your own values, for instance adding an
ExecPreStart or a
Requires. The above example uses the
systemctl edit function, which automatically creates these overrides, but you can drop these files in manually too using your configuration management of choice.
#6 – Targets – group services, mounts, etc. together
Target units are another really cool feature of Systemd. You've probably seen stuff like
Reached multi-user.target in your boot logs, but you can of course create your own
targets as well. Simply put, they group other units together. If two services and a mount are part of a target, the target won't be reached until all of them start, and you can, with a few modifications to the units – using
PartOf = mytarget.target in the
[Unit] section of the services/mounts – control all the services by stopping or starting the target itself, in the right order. Depend other services on targets as well for maximum control of the startup sequence. There's a ton of power here.
systemctl enable and
This is a really basic one, but want to turn off a service or mount for a bit? Disable it! Want a service that is installed by default (such as
nginx), but want to start it with
supervisord instead and are getting a conflict? Disable it!
#8 – PIDFile
A nice thing about Systemd is that you don't ever have to worry about PID files, including weird stale PIDfiles lying around and messing with your service startup. But still want one? You can still add one with
Edit: this did the opposite thing I thought it did, ignore it.
#9 – Sockets units can replace [x]inetd
The old style, "run a script on a socket connection" tool inetd and its modern successor xinetd can be replaced by systemd
.socket units, bringing the ease of use and control of Systemd to your inetd services!
Those are the first 9 I can think of right now, but if you have any of your own cool systemd tricks, I'd love to hear them too!