Recently, I had a chance to write systemd unit files for the daemon processes that run as part of Beaker: beakerd which is the scheduling daemon running on the server and the four daemons running on the lab controller – beaker-proxy, beaker-provision, beaker-watchdog and beaker-transfer.
beakerd’s unit file
Here is the systemd unit file for beakerd, which I will use to illustrate the core points of this post. The other unit files are similar, and hence I will explain only where they differ from this one:
[Unit] Description=Beaker scheduler After=mysqld.service [Service] Type=forking PIDFile=/var/run/beaker/beakerd.pid ExecStart=/usr/bin/beakerd User=apache Group=apache [Install] WantedBy=multi-user.target
The [Unit] section has a description of the service (using the Description option) and specifies that it should start after the mysqld.service has started using the After option. beakerd needs to communicate to a MySQL server before it can start successfully. It can work with a local or a remote MySQL server. Hence, specifying After sets up an ordering that if there is a local MySQL server, then wait for it to start before starting beakerd. Using Requires is not suitable here to accommodate the possibility that beakerd may be configured to use a remote MySQL server.
In the [Service] section, the Type is set to Forking. This is because, beakerd uses python-daemon which forks itself (detaches itself) during the daemonization. However, you must ensure that when creating a
DaemonContext() object, you should specify
detach_process=True. This is because, if python-daemon detects that it is running under a init manager, it doesn’t detach itself unless the keyword is explicitly set to True, as above (you can see the code in
daemon.py). Hence, although not setting the above keyword would work under SysV Init, it doesn’t work under systemd (with Type=Forking), since the daemon doesn’t fork at all and systemd expects it to fork (and finally kills it). The PIDFile specifies where the process ID is dumped by beakerd and is setup while creating the DaemonContext object as follows and ExecStart specifies the location to the binary that is to be started.
The beakerd process is to be run as the apache user and group, which is specified by the User and Group options.
In the [install] section, the WantedBy option specifies when the beakerd process should be started (similar to the concept of “run levels” in SysV init). systemd defines several targets, and here we define that we want beakerd to start as part of the multi user setup.
That’s all about beakerd’s unit file.
beaker-provision’s unit file
beaker-provision and the other daemons running on the lab controller have similar unit files:
[Unit] Description=Beaker provisioning daemon After=httpd.service [Service] Type=forking PIDFile=/var/run/beaker-lab-controller/beaker-provision.pid ExecStart=/usr/bin/beaker-provision User=root Group=root [Install] WantedBy=multi-user.target
All the four lab controller daemons need to communicate with Beaker web application – which can be local or remote, and hence the After option specifies the dependency on httpd.service. And, this particular daemon runs as root user/group, which is specified by the User and group options.
And everything else is similar to beakerd’s unit file and also the other lab controller daemons.
Shipping SysV init files and systemd unit files in the same package
The beaker packages ship both init files and systemd unit files now so that it can use systemd when available, but use SysV init otherwise. This commit can give you some idea of how to go about it.
These links proved helpful to learn more about systemd, including how to package unit files for Fedora: