Adding Custom Services With systemd

systemd is a system and service manager for Linux similar to SysV init. Several Linux distributions, notably Red Hat Enterprise Linux, SuSE, CentOS, Fedora, Debian and Ubuntu, are adopting it for their current or future releases. You can now experience systemd on Fedora and Red Hat Enterprise Linux 7 Beta.

We decided to install customized versions of Apache httpd and Percona Server, both of which must be started on boot.  systemd configurations had to be created for these.  We based our configuration files on existing ones for Apache httpd and MySQL. Furthermore, we made sure that necessary directories for these software are created at boot time.

The procedures described below were done on a VMware installation of Red Hat Enterprise Linux 7 Beta. These procedures should work on Fedora 20 as well (we’ll verify this in the future).

First, we compile and install Apache httpd version 2.4.9 (we’ll write an article about this in the future). Our installation of Apache httpd is in /opt/apache. The configuration files are in /etc/opt/apache while the logs are in /var/opt/apache.  Note that this layout of the installation is the opt layout for Apache httpd which is specified during configuration of the source.

Let us take a look at the systemd configuration file for the built-in Red Hat httpd daemon:

[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target

[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

The above file, named httpd.service, is found in /usr/lib/systemd/system.

We now create another file which we name as apache-httpd.service and place in /usr/lib/systemd/system. Note that we must make sure that httpd.service is disabled. Let us disable it using the command:

sudo systemctl disable httpd.service

To check the status of a service, we can type the following command:

sudo systemctl status httpd.service

Now, our apache-httpd.service file for the custom Apache httpd installation contains the following:

[Unit]
Description=The Apache HTTP Server (akumubuild)
After=network.target remote-fs.target nss-lookup.target percona-server.service

[Service]
#Type=notify
Type=forking
#Type=dbus
#BusName=com.redhat.apache-httpd
EnvironmentFile=/etc/sysconfig/apache-httpd
#ExecStart=/opt/apache/sbin/httpd $OPTIONS -DFOREGROUND
ExecStart=/opt/apache/sbin/httpd $OPTIONS 
ExecReload=/opt/apache/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
PIDFile=/var/opt/apache/run/httpd.pid

[Install]
WantedBy=multi-user.target

The original httpd.service was used as a template. Note the differences. For apache-httpd.service, we allow httpd to fork. The Reload command does not use a kill command. Instead, '-k graceful' is passed to httpd.  Note that we also refer to the percona-server.service which we will discuss later.

We enable apache-httpd.service using ‘sudo systemctl enable apache-httpd.service‘.  Again, use the status command of systemctl to check on the service.  If it isn’t started, try using ‘sudo systemctl start apache-httpd.service‘.  The ‘enable‘ command makes sure that the service is started at boot time while ‘start‘ simply runs the service.

We should see the following by checking the status (‘sudo systemctl status apache-httpd’) of our custom installation of Apache httpd:

apache-httpd.service - The Apache HTTP Server (akumubuild)
   Loaded: loaded (/usr/lib/systemd/system/apache-httpd.service; enabled)
   Active: active (running) since Thu 2014-04-03 00:44:31 EDT; 1 day 17h ago
 Main PID: 1942 (httpd)
   CGroup: /system.slice/apache-httpd.service
           ├─1942 /opt/apache/sbin/httpd
           ├─1998 /opt/apache/sbin/httpd
           ├─1999 /opt/apache/sbin/httpd
           ├─2048 /opt/apache/sbin/httpd
           ├─2049 /opt/apache/sbin/httpd
           ├─2050 /opt/apache/sbin/httpd
           └─3237 /opt/apache/sbin/httpd

Apr 03 00:44:30 akumu.hq.linuxunbound.com systemd[1]: PID file /var/opt/apache/run/httpd.pid not re...rt.
Apr 03 00:44:31 akumu.hq.linuxunbound.com systemd[1]: Started The Apache HTTP Server (akumubuild).
Hint: Some lines were ellipsized, use -l to show in full.

Some things to consider:

  • Make sure the file /etc/sysconfig/apache-httpd exists.  This doesn’t have to contain anything though you can add some optional parameters to httpd by assigning them to the shell variable OPTIONS.
  • The directories /var/opt/apache/logs and /var/opt/apache/run must exist.

Percona Server

The MySQL-compatible Percona Server should have the following configuration file in /usr/lib/systemd/system named percona-server.service:

[Unit]
Description=The Percona Server (MySQL)
# See https://bugzilla.redhat.com/show_bug.cgi?id=714426
After=network.target remote-fs.target nss-lookup.target
Before=apache-httpd.service

[Service]
#Type=notify
#Type=forking
#Type=dbus
Type=simple
EnvironmentFile=/etc/sysconfig/percona-server
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --user=mysql $OPTIONS 
#ExecStop=/usr/local/mysql/bin/mysqladmin -u root -p shutdown
ExecStop=/bin/kill -TERM ${MAINPID}
ExecReload=/bin/kill -HUP ${MAINPID}

PrivateTmp=true
PIDFile=/var/run/mysqld/mysqld.pid

[Install]
WantedBy=multi-user.target

Again, we must make sure that certain files and directories exist:

  • the file /etc/sysconfig/percona-server
  • the directory /var/log/mysqld (or whatever is specified in /etc/my.cnf)
  • the directory /var/run/mysqld

Take note that /var/run/mysqld is a temporary directory that is created at boot time and deleted at shutdown.  We need to create a file called /etc/tmpfiles.d/percona.conf which contains the following:

d /run/mysqld 0755 mysql mysql -

This configuration file creates the directory /run/mysqld with mode 0755 and ownership by user ‘mysql‘ and group ‘mysql‘.

Enable the Percona Server service using systemctl as you did for Apache httpd.  Once it is running, you should see something like this status:

percona-server.service - The Percona Server (MySQL)
   Loaded: loaded (/usr/lib/systemd/system/percona-server.service; enabled)
   Active: active (running) since Thu 2014-04-03 00:44:28 EDT; 1 day 17h ago
 Main PID: 1842 (mysqld)
   CGroup: /system.slice/percona-server.service
           └─1842 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --user=mysql

Apr 03 00:44:28 akumu.hq.linuxunbound.com systemd[1]: Started The Percona Server (MySQL).

More information on systemd can be found on their wiki.

About

I have been using Linux since 1993 as a systems administrator. I consult for companies that need support and administration of their networks of Linux servers. I also work with Mac OS X and Windows, integrating them in networks with Linux servers. Linux Unbound is a project of mine dedicated to Linux and Linux-related topics.

Tagged with: , , , , , , ,