Understanding systemd units

On the Unit

Article from Issue 214/2018
Author(s):

Systemd units use files to control resources that Systemd manages.

Whether you like it or not: Systemd has become ubiquitous. Linux distributions that rely on other init systems are becoming increasingly rare. If you run one of the mainstream distributions, you need to familiarize yourself with the concepts and working methods of systemd.

Systemd units and their corresponding configuration files require close attention. The term "unit" means any type of resource that cooperates with Systemd – which includes timers, mountpoints, network resources, sockets, partitions, and devices on top of services.

Configuration units, known as unit files, let you define how and when a service starts, which resources it is allowed to access, and which dependencies need to be met. Unit files are similar in function to the init scripts in SysVinit or Upstart (Figure 1), but they are usually easier to create and easier to maintain. They follow the conventions of simple INI files (Figure 2).

Figure 1: Init scripts from SysVinit are monolithic, long, and difficult to read. Autofs contains over 100 lines.
Figure 2: The autofs unit file is clear, concise, and relatively easy to read.

The naming convention for unit files follows the pattern Name.type. Table 1 shows a selection of the most frequently encountered types. As you can see, Systemd manages many different unit types.

Table 1

Unit Types

Type

Function

.service

Start, monitor and stop services

.device

Create device files

.mount

Mount and unmount mountpoints

.automount

Automatically mount and unmount mountpoints

.target

Define a group of units

.timer

Define recurring tasks (like Cron)

.socket

Establish connections between processes

.network

Configure networks

.path

Execute service units as a function of changes

Many of the unit types work together to extend functionality. Some units are used to trigger other units and activate services and targets. Each type has its own man page – named according to the pattern systemd.type.

Distributed

Units are found in several places on the system. Under /lib/systemd/system/ are files pre-installed by the system. Units you created yourself, or units you edited, are found in /etc/systemd/system/. If you want to change an existing unit, it is best to copy it there first and edit it there. Finally, certain units relevant for the runtime are located below /run/system/system/. The order of parsing is /etc/, /run/, /lib/.

When you look at the unit files gathered in /lib/systemd/system/, you will see files with different extensions that represent the different types. Extensions like .network, .timer, .mount, or .device are self-explanatory. However, the service units that determine the behavior of the services on the computer are the most common type (Figure 3).

Figure 3: Unit files for services ending in .service are the most common.

Tripartite

An example helps to explain the structure of the files. This example is based on the autofs.service service shown in Figure 2. autofs.service is a service for starting external drives or network shares, and it uses a reasonably clear unit file.

A unit is divided into three sections [Unit], [Type], and [Install]; the unit type varies. In this case, it says [Service] because it is a unit for controlling a service. Often several unit types belong together, such as a service and a timer. The service file defines the service itself, and the timer controls its recurring execution (Figure 4).

Figure 4: Self-created timers like etckeeper and fstrim complement the timers created by Systemd.

In the example from Listing 1, the directives used with the unit take the form of key-value pairs. This section is typically used to define metadata for the unit and to configure the relationship of the unit to other units.

Listing 1

Unit Section

[Unit]
Description=Automounts filesystems on demand
After=network.target ypbind.service sssd.service network-online.target remote-fs.target
Wants=network-online.target

The Description key describes the service. You are free to choose the value, but it should clearly state the purpose of the service. The After key contains the services and targets that this service expects. Targets are groups of services (Figure 5).

Figure 5: Targets group several units and may themselves be based on other targets. The AllowIsolate=yes directive allows this target to act as a boot target.

The last key you see is Wants, which you use to denote optional dependencies. You indicate a hard dependency with Require. If the service registered there does not start, the service to which this unit belongs fails. If you specify Wants, it will still start. Now, if you're wondering what the extra After is for: Its absence would mean that both units would start in parallel, which would not make sense in this case.

In the Unit section, you can use further keywords like Description, Documentation, BindsTo, Conflicts, Condition, Assert and others. For more information, see the systemd.units man page.

The [Service] section plays a central role (Listing 2). First, you need to define the service type. The default is Type=simple. The simple type means that the service does not fork after startup.

Listing 2

Service Section

[Service]
Type=forking
PIDFile=/var/run/autofs.pid
EnvironmentFile=-/etc/default/autofs
ExecStart=/usr/sbin/automount
ExecReload=/bin/kill -HUP $MAINPID
TimeoutSec=180

The example in Listing 2 is a forking type service. Systemd considers the service to have started as soon as the process disappears into the background and the higher-level system terminates. This type is often used for legacy daemons. You need to specify the key-value pair PIDFile=File, so that the system can continue to follow the main process.

You might encounter a few other service types when you look at the unit files on your computer. Type=oneshot is used for scripts that do a single job and then exit. Type=notify is similar to Type=simple, with the difference that the daemon sends a signal to Systemd when it is ready. In the case of Type=dbus, the service is considered ready if the specified BusName appears on the D-bus system bus. In the case of Type=idle, Systemd delays the execution of the service until it has completed all other pending jobs.

Another key from this example, EnvironmentFile=, appears in the [Service] section. This value refers to a file from which the service loads environmental variables if required. ExecStart= contains the command that the system executes when the unit starts, and ExecReload= reloads the configuration of the service if necessary.

Finally, TimeoutSec= specifies the maximum time the service will run. All service types and keys for the [Service] section are explained in detail in the systemd.service man page.

The [Install] section in this example has only a single entry (Listing 3). The key-value pair used here is present in almost every service file. The WantedBy key determines when the unit starts. The multi-user.target value is the default for a multi-user system. These targets correspond to the run levels in SysVinit, where multi-user.target stands for run level 3.

Listing 3

Install Section

[Install]
WantedBy=multi-user.target

You can determine the run level in Systemd using systemctl get-default in the terminal. In a graphical environment, it goes by the name of graphical.target (SysVinit: Run-Level 5). All available run levels (or, more correctly, targets) are displayed by the command

ls -al /lib/systemd/system/runlevel*

See Figure 6.

Figure 6: The runlevels used in previous init systems find a counterpart in Systemd targets.

Author It Yourself?

You may have wondered what practical reason (besides pure curiosity) would make you want to create a Systemd unit.

Suppose you install some software that runs a service that only has an init file, but not a unit file: It makes sense to create a unit for it yourself. A good starting point is the simple template in Listing 4.

Listing 4

A Template

[Unit]
Description=My_Unit
Documentation=man:optional reference to man files<I>
After=<I>starts after XY<I>
Wants=optional <I>dependencies<I>
[Service]
<I>Key-value pairs for the unit type in question<I>
[Install]
WantedBy=multi-user.target

A useful way to fill the [Service] section is to look at similar existing unit files. The systemctl list-unit-files command creates a list of all unit files on the system with their current statuses. You can restrict this list to services by specifying systemctl list-unit-files --type service.

However, the first command can return other interesting unit types of the same name. These could be target units, for example: They are used to link and group other units to describe a desired state of the system. Some of these units would then be services, others perhaps additional targets with their own groups of units.

Users who rely on KDE Plasma enjoy greater convenience: This desktop lists all units and their statuses clearly in the system settings below the System item. You can also use a combo box to filter by unit type or use a search function (Figure 7).

Figure 7: The Systemd menu item in the KDE Plasma settings provides an overview of units running on the system and their current statuses. You can use the context menu to control units, as you would with the systemctl command-line utility.

To learn more about a unit similar to the one you are creating, use the systemctl status service_name command in addition to the unit file. This command provides information about runtime, memory usage, process ID (PID), and possible error messages since the last start of the service (Figure 8).

Figure 8: Querying the status of a unit facilitates troubleshooting.

Once you have finished the unit file and put it in the right place, use systemctl status service_name to check the status. Additional information may be provided by the journalctl --unit=service_name command.

To enable and start the service, use the systemctl start service_name command. The systemctl man page provides additional commands and options.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Systemd GUIs

    Graphical frontends make it easier to take full advantage of the Systemd process manager. We examine some leading tools for the KDE environment.

  • Systemd Timers

    Systemd can start timers that automatically perform tasks at specified times. The configuration files are known as timer units.

  • Packages in systemd

    You might need to tweak your Debian or Ubuntu packages to get them to work with systemd.

  • Working the System

    Every major aspect of a system that runs in userland can be controlled by systemctl, a command that acts on systemd's units.

  • Command Line: Systemd

    Wondering what all the fuss is about systemd? We explain the basic concepts and capabilities of the new system management suite – coming soon to a distro near you.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News