4th July 2017
Systemd, tmpfiles.d, and /var/run
Managing PID files on CentOS 7, with particular regard to packaging and Systemd.
Some of this article is to do with Systemd, at least in part. Mainly, however, it's just a writeup of some things I learned recently about packaging RPMs for CentOS 7 (or RedHat 7), particularly when it comes to dealing with servicename.pid
files.
To some, Systemd can strike you as an unfamiliar, unfriendly and unhelpful replacement to old fashioned but simple /etc/init.d/servicename start|stop
scripts. It does have additional features, as well as new annoyances, but the fact is that it's here in most of the major GNU/Linux distributions, and is likely to be around for some time, so it's worth taking some time to get familiar with it and get to know some of its quirks.
This is a writeup of one quirk that I discovered today, so I thought I would write it up for others.
Meet the Cast
The main players in this particular story are as follows - the actual application doesn't necessarily make much of a difference:
- JBoss Web Server
- PID files in
/var/run/jws
- Systemd to start, stop and manage the service
- Packaging the above into an RPM
How to Package These
In a nutshell, your RPM package needs to include:
- A
/var/run/jws
directory, owned by the application user (eg, "tomcat") - A
/usr/lib/tmpfiles.d/jws.conf
file, which defines how that directory is to be created after a reboot. It should look something like this:
d /var/run/jws 0755 tomcat tomcat -
- A
/usr/lib/systemd/system/jws.service
unit file, telling Systemd to start the service as "tomcat", with a line like this:
User=tomcat
The first is so that /var/run/jws
is created when the package is installed, and has the correct permissions. When you start up the service, it can run as the "tomcat" user, and create its /var/run/jws/jws.pid
file without any problems.
The second is because after you reboot the server, /var/run
disappears along with all of its contents - it is a transient file system. The tmpfiles
service will create the directory for you after a reboot. The entries in the /usr/lib/tmpfiles.d/jws.conf
file are relatively obvious: "d" for Directory, then the name of the directory, its access mode (0755 seems reasonable), owner "tomcat" and group "tomcat". Finally, and very importantly, the age ("-") tells tmpfiles
never to delete the directory. By default, tmpfiles
will periodically prune any old temporary files that it finds lying around; you do not want this to happen to your PID file.
The third means that the entire service can be started as a non-privileged "tomcat" user, which doesn't need to be root
to write to /var/run
directly; it's silly to run it (even if only at start and finish) as root when it doesn't really need that level of access.
Summary
What this means, really, is that you need to tell the system about the /var/run/jws
directory twice: Once in the RPM itself, and then again via tmpfiles
to allow for the fact that the directory created when the RPM is installed will only last until the server is next rebooted, so some other mechanism is required to create after a reboot. Is this annoying? Yes. Is it the end of the world? No. But it is certainly worth making a note of.
Systemd File Locations
One thing that Systemd does fairly consistently and sensibly, once you get the hang of it, is file locations. At least in RedHat/CentOS, but I believe generally, packages should install their *.service
files, tmpfiles.d/*.conf
files, and so on, under /usr/lib
. Systemd will also read /etc
equivalents, which override /usr/lib
. The implication of this is that packages can control, change and upgrade their own configurations, but a local system administrator can override them by putting alternative settings in /etc
.
Footnote
I have a lot still to learn about the oddities of Systemd; please do get in touch if I have missed anything, or got anything wrong here.
Invest in your career. Buy my Shell Scripting Tutorial today: