Customising systemd unit files
systemd is now one of the most common init systems used on Linux. It's also become the default init system for a range of Linux distributions including CentOS, Debian, and Amazon Linux 2.
One of the great things about systemd is unit files can easily be modified to control how a service is launched. This post is going to look at customising unit file configuration, while still playing nice with the system package manager.
Adding a CPU quota to Apache
On CentOS, the unit file for the httpd
service is
/usr/lib/systemd/system/httpd.service
, and has contents similar to the
following:
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd(8)
Documentation=man:apachectl(8)
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true
[Install]
WantedBy=multi-user.target
For the example in this post, I'm going to show a few different ways to add the following configuration:
[Service]
CPUQuota=40%
This configuration will limit Apache's maximum CPU usage to 40% of a core. For more info, have a look at the systemd documentation on resource control.
Adding the new config directly
It's tempting to modify /usr/lib/systemd/system/httpd.service
directly:
@@ -5,6 +5,7 @@
Documentation=man:apachectl(8)
[Service]
+CPUQuota=40%
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
While this will work initially there is a big drawback, the file is not marked as a config file:
$ rpm --query --configfiles httpd |grep httpd.service
$
As a result, if httpd
is updated the configuration change will be overridden!
Copying the unit file
To avoid the problem above, custom configuration should be placed in
/etc/systemd/system/
, this configuration will the be read instead of the
configuration in /usr/lib/systemd/system/
. Therefore you can just copy and
modify the configuration file:
cp -p /usr/lib/systemd/system/httpd.service /etc/systemd/system/
sed -i '/^\[Service\]/aCPUQuota=40%' /etc/systemd/system/httpd.service
systemctl daemon-reload
This will work fine, however there is a slight drawback. If a later version of
the httpd
package modifies the unit file, systemd will ignore the changes
until you manually copy them over to /etc/systemd/system/httpd.service
.
Using .include
Instead of just copying the file, a better approach is to include the system
default file using .include
, and then add any custom configuration. This can
be done by adding configuration similar to the following to
/etc/systemd/system/httpd.service
:
.include /usr/lib/systemd/system/httpd.service
[Service]
CPUQuota=40%
Once the config has been updated, don't forget to reload the unit file:
systemctl daemon-reload
systemctl show
can then be used to check the new configuration option has
been picked up correctly:
$ systemctl show httpd.service --property=CPUQuotaPerSecUSec
CPUQuotaPerSecUSec=400ms