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.
#3 - ExecPreStart/ExecPostStart and similar Stop commands
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.
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 /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 /lib into /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.
#7 - systemctl enable and systemctl disable
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 PIDFile=.
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!