Systemd Services 101

Tutorials – Systemd

Systemd is the init system of almost all modern Linux distributions. It's the first process to start when Linux boots up, and it controls everything else that runs on your computer. Much of this happens automatically, and you should never have to think about it, but there are some bits that you may wish to poke around from time to time.

Before we get too far in, the first thing to do is check if you're using systemd. You can do so with the command:

pidof systemd

If this returns a number, then you're running on a systemd distro, if there's no output, then you're using some other init system. To follow along with this tutorial, you'll need systemd, so you may want to download a live distro such as Ubuntu and run it in a virtual environment.

I mentioned that systemd controls everything that runs on your computer. It does this through services, which are normal bits of software that systemd starts automatically at a predetermined point. For example, if you're using a desktop environment, systemd will launch your login manager once the graphical system has started. This login manager starts your desktop and your desktop starts your graphical software. You can see how everything branches out of systemd with the command:

pstree -p

Systemd decides what to launch by looking at the service files. If you're familiar with the old style SysVinit, these service files take the place of the init.d scripts, but they're a very different syntax.

Let's look at this by creating our own service. In general, services are bits of software that run indefinitely, and ours will be no different. It's a hello world service that just outputs "hello world" every 30 seconds (Figure 1). Create a text file called hws.sh in your home directory with the following:

#!/bin/bash
while $(sleep 30);
do
echo "hello world"
done

Figure 1: System services don't have to be complex, and ours is only six lines long.

Make this file executable with:

chmod a+x hws.sh

You can now run this from the command line with ./hws.sh, but that's not running it as a service. Now let's look at how to get systemd to start this automatically every time you start your computer.

The service files are typically split into two sections, Unit and Service. The Unit section has the basic information about what this file is for and when to run it. The Service section contains details about what actually we want to run. A basic service file for our Hello World Service is:

As you can see, this contains a description that can be anything you want. The After line tells systemd when to start this service by telling it what needs to be started before this one can. We're just waiting for the user sessions to start, although really, this could be started earlier if desired.

Setting Type to simple tells systemd that this is a command that will continue to run in the session it was started. The alternative here is Type=forking, which is for commands that handle their own daemonization. You can think of this in terms of running something from the command line. If, when you run a command, it continues to send output to the terminal, it's a simple type, whereas if the commands kick of some background processes and return the command prompt, then it's a forking type. The final line here is just the command to run.

Save this in a file called hws.service (the filename is important in this case), and then copy this file to /etc/systemd/system (you may need to use sudo). Once this is in place, you can start the service with:

systemctl start hws.service

Once that's finished, your hello world service is running in the background greeting the rest of the planet. All the output from processes started like this is gobbled by another part of systemd: journald. You can view this with the command:

systemctl status hws

This will show you the last few log lines as well as information about the processes running. You can also view the entire log with:

journalctl -u hws -e

The -u flag tells journalctl which unit (that is, service file) to show the output of, and the -e flag means start from the end of the file and work backwards. By default, this will show the log in a scrollable environment, but if you pipe the command into something else (e.g., grep), then it will send the text to stdout.

Most distributions also send the output from systemd services to the syslog. This is an option in systemd rather than a fixed feature, and we may find that over time, this happens in fewer and fewer distros as people become used to working with journalctl rather than the logfiles.

Let's take a look at these journald lines. You should have seen something like this:

Obviously, the first section is the date. The next item in the line is the machine that this happens on. Although it might initially seem obvious which machine it's running on, this isn't always the case as logs are often amalgamated into a centralized logging system. The next bit is the name of the software that's running and the process identifier. The final bit is the actual output.

Most of this output looks quite good, but the hws.sh part isn't very clear. We could rename the file that runs, but we don't need to. Instead, we can just tell systemd to use something else in the logging. This is the syslog identifier. If you include the following line in the Service section of the hws.service file, it will replace hws.sh with something more meaningful:

SyslogIndentifier=HelloWorldService

We've only looked at the most basic options here, and there are many more advanced features. Most of them are as simple as setting options in the service file, and the process is well documented in the systemd.exec man page (Figure 2). See the "Systemd Timers" box for more information.

Systemd Timers

In this tutorial, we've looked at services that start and then continue to run. However, there's another type of background program: scheduled tasks. These we want to run periodically rather than constantly. You can use cron, but systemd provides tools for this. First, you need to create a service file as we have done in the main tutorial; then you need a timer file, which should have the same name as the service file but with the .timer ending. This is saved in the same directory as the service file. A simple Timer file that would run our hello world service (even if it stopped running or didn't have a loop to continue to run) is:

As you can see, you can time relative to booting as well as on pre-defined periods.

Figure 2: You can find out how to extend your service files to take advantage of the full range of options on the systemd.exec man page.

Systemd has made it much easier to create services, especially for people not skilled in the dark art of Bash scripting. As you've seen, a simple service file isn't scary; it's just a place to tell systemd what you want to do. You should be able to take the skills we've covered in this tutorial and apply them to running almost any software as a service. Don't fear the daemon.