SystemD - Understanding the Unit File Structure (part 5)

SystemD - Understanding the Unit File Structure (part 5)

5 Understanding the Unit File Structure

We need understand the unite file structure. A unit configuration file encodes information about a service, a socket, a device, a mount point and more. Each unit file is a simple text file describing a unit, what it does, what needs to run before or afterward, and other details.

A unit configuration file encodes information about a service, a socket, a device, a mount point, an automount point, a swap file or partition, a start-up target, a watched file system path, a timer controlled and supervised by systemd(1), a resource management slice or a group of externally created processes.

The files that define how systemd will handle a unit can be found in many different locations, each of which have different priorities and implications.

5.1 Location of systemd unit files

  • /lib/systemd/system - The system's copy of unit files are generally kept in this directory. When software installs unit files on the system, this is the location where they are placed by default.
  • /run/systemd/system - Systemd unit files created at run time. This directory takes precedence over the directory with installed service unit files.
  • /etc/systemd/system/ - If you wish to modify the way that a unit functions, the best location to do so is within this directory. Unit files found in this directory location take precedence over any of the other locations on the filesystem. If you need to modify the system's copy of a unit file, putting a replacement in this directory is the safest and most flexible way to do this.

Example of postfix.service unit file in debian stretch from /lib/systemd/system/postfix@.service file:

[Unit]
Description=Postfix Mail Transport Agent (instance %i)
Documentation=man:postfix(1)
PartOf=postfix.service
Before=postfix.service
ReloadPropagatedFrom=postfix.service
After=network-online.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
GuessMainPID=no
ExecStartPre=/usr/lib/postfix/configure-instance.sh %i
ExecStart=/usr/sbin/postmulti -i %i -p start
ExecStop=/usr/sbin/postmulti -i %i -p stop
ExecReload=/usr/sbin/postmulti -i %i -p reload

[Install]
WantedBy=multi-user.target

5.2 Unit files section

Unit files typically consist of three section:

  • [Unit] — contains generic options that are not dependent on the type of the unit. These options provide unit description, specify the unit's behavior, and set dependencies to other units. For a list of most frequently used [Unit] options, see Important [Unit] section Options
  • [unit type] — if a unit has type-specific directives, these are grouped under a section named after the unit type. For example, service unit files contain the [Service] section. See Important [Service] Section Options for most frequently used [Service] options.
  • [Install] — contains information about unit installation used by systemctl enable and disable commands. See Important [Install] Section Options for a list of [Install] options.

Important [Unit] section Options:

  • Description - A meaningful description of the unit. This text is displayed for example in the output of the systemctl status command.
  • Documentation - Provides a list of URIs referencing documentation for the unit.
  • Requires - Configures dependencies on other units. The units listed in Requires are activated together with the unit. If any of the required units fail to start, the unit is not activated. These units are started in parallel with the current unit by default.
  • Wants - Configures weaker dependencies than Requires. If any of the listed units does not start successfully, it has no impact on the unit activation. This is the recommended way to establish custom unit dependencies.
  • Conflicts - Configures negative dependencies, an opposite to Requires. This can be used to list units that cannot be run at the same time as the current unit. Starting a unit with this relationship will cause the other units to be stopped.
  • Before - The units listed in this directive will not be started until the current unit is marked as started if they are activated at the same time. This does not imply a dependency relationship and must be used in conjunction with one of the above directives if this is desired.
  • After (B) - Defines the order in which units are started. The unit starts only after the units specified in After are active. Unlike Requires, After does not explicitly activate the specified units. The Before option has the opposite functionality to After.
  • Condition - There are a number of directives that start with Condition which allow the administrator to test certain conditions prior to starting the unit. This can be used to provide a generic unit file that will only be run when on appropriate systems. If the condition is not met, the unit is gracefully skipped.
  • Asert - Similar to the directives that start with Condition, these directives check for different aspects of the running environment to decide whether the unit should activate. However, unlike the Condition directives, a negative result causes a failure with this directive.

Important [Service] Section Options

  • Type - Configures the unit process startup type that affects the functionality of ExecStart and related options. One of:
  • simple – The default value. The process started with ExecStart is the main process of the service.
  • forking – The process started with ExecStart spawns a child process that becomes the main process of the service. The parent process exits when the startup is complete.
  • oneshot – This type is similar to simple, but the process exits before starting consequent units.
  • dbus – This type is similar to simple, but consequent units are started only after the main process gains a D-Bus name.
  • notify – This type is similar to simple, but consequent units are started only after a notification message is sent via the sd_notify() function.
  • idle – similar to simple, the actual execution of the service binary is delayed until all jobs are finished, which avoids mixing the status output with shell output of services.
  • ExecStart - Specifies commands or scripts to be executed when the unit is started. ExecStartPre and ExecStartPost specify custom commands to be executed before and after ExecStart. Type=oneshot enables specifying multiple custom commands that are then executed sequentially.
  • ExecStop - Specifies commands or scripts to be executed when the unit is stopped.
  • ExecReload - Specifies commands or scripts to be executed when the unit is reloaded.
  • Restart - With this option enabled, the service is restarted after its process exits, with the exception of a clean stop by the systemctl command.
  • RemainAfterExit - If set to True, the service is considered active even when all its processes exited. Default value is False. This option is especially useful if Type=oneshot is configured.

Important [Install] Section Options

  • Alias - Provides a space-separated list of additional names for the unit. Most systemctl commands, excluding systemctl enable , can use aliases instead of the actual unit name.
  • RequiredBy - A list of units that depend on the unit. When this unit is enabled, the units listed in RequiredBy gain a Require dependency on the unit.
  • WantedBy - A list of units that weakly depend on the unit. When this unit is enabled, the units listed in WantedBy gain a Want dependency on the unit.
  • Also - Specifies a list of units to be installed or uninstalled along with the unit.
  • DefaultInstance - Limited to instantiated units, this option specifies the default instance for which the unit is enabled. See

5.3 Examples

5.3.1 Environment directive

Systemd has an Environment directive which sets environment variables for executed processes. It takes a space-separated list of variable assignments. This option may be specified more than once in which case all listed variables will be set. If the same variable is set twice, the later setting will override the earlier setting. If the empty string is assigned to this option, the list of environment variables is reset, all prior assignments have no effect.

example:

[Service]
# Client Env Vars
Environment=ETCD_CA_FILE=/path/to/CA.pem
Environment=ETCD_CERT_FILE=/path/to/server.crt
Environment=ETCD_KEY_FILE=/path/to/server.key
# Peer Env Vars
Environment=ETCD_PEER_CA_FILE=/path/to/CA.pem
Environment=ETCD_PEER_CERT_FILE=/path/to/peers.crt
Environment=ETCD_PEER_KEY_FILE=/path/to/peers.key

5.3.2 EnvironmentFile directive

EnvironmentFile similar to Environment directive but reads the environment variables from a text file. The text file should contain new-line-separated variable assignments.

For example, in Container Linux, the coreos-metadata.service service creates /run/metadata/coreos. This environment file can be included by other services in order to inject dynamic configuration. Here's an example of the environment file when run on DigitalOcean (the IP addresses have been removed):

COREOS_DIGITALOCEAN_IPV4_ANCHOR_0=X.X.X.X
COREOS_DIGITALOCEAN_IPV4_PRIVATE_0=X.X.X.X
COREOS_DIGITALOCEAN_HOSTNAME=test.example.com
COREOS_DIGITALOCEAN_IPV4_PUBLIC_0=X.X.X.X
COREOS_DIGITALOCEAN_IPV6_PUBLIC_0=X:X:X:X:X:X:X:X

This environment file can then be sourced and its variables used. Here is an example drop-in for etcd-member.service which starts coreos-metadata.service and then uses the generated results:

[Unit]
Requires=coreos-metadata.service
After=coreos-metadata.service

[Service]
EnvironmentFile=/run/metadata/coreos
ExecStart=
ExecStart=/usr/bin/etcd2 \
  --advertise-client-urls=http://${COREOS_DIGITALOCEAN_IPV4_PUBLIC_0}:2379 \
  --initial-advertise-peer-urls=http://${COREOS_DIGITALOCEAN_IPV4_PRIVATE_0}:2380 \
  --listen-client-urls=http://0.0.0.0:2379 \
  --listen-peer-urls=http://${COREOS_DIGITALOCEAN_IPV4_PRIVATE_0}:2380 \
  --initial-cluster=%m=http://${COREOS_DIGITALOCEAN_IPV4_PRIVATE_0}:2380

5.3.3 RestartSec directive

Configures the time to sleep before restarting a service (as configured with Restart below). Takes a unit-less value in seconds, or a time span value such as "5min 20s". Defaults to 100ms.

5.3.4 Restart directive

Configures whether the service shall be restarted when the service process exits, is killed, or a timeout is reached. The service process may be the main service process, but it may also be one of the processes specified with ExecStartPre, ExecStartPost, ExecStop, ExecStopPost, or ExecReload.
When the death of the process is a result of systemd operation (e.g. service stop or restart), the service will not be restarted. Timeouts include missing the watchdog keep-alive ping deadline and a service start, reload, and stop operation timeouts.

Restart directive one of this arguments:

  • no - If set to no (the default), the service will not be restarted.
  • on-sucess - If set to on-success, it will be restarted only when the service process exits cleanly. In this context, a clean exit means an exit code of 0, or one of the signals SIGHUP, SIGINT, SIGTERM or SIGPIPE, and additionally, exit statuses and signals specified in SuccessExitStatus directive.
  • on-failure - If set to on-failure, the service will be restarted when the process exits with a non-zero exit code, is terminated by a signal (including on core dump, but excluding the aforementioned four signals), when an operation (such as service reload) times out, and when the configured watchdog timeout is triggered.
  • on-abnormal - If set to on-abnormal, the service will be restarted when the process is terminated by a signal (including on core dump, excluding the aforementioned four signals), when an operation times out, or when the watchdog timeout is triggered.
  • on-abort - If set to on-abort, the service will be restarted only if the service process exits due to an uncaught signal not specified as a clean exit status. If set to on-watchdog, the service will be restarted only if the watchdog timeout for the service expires.
  • always - If set to always, the service will be restarted regardless of whether it exited cleanly or not, got terminated abnormally by a signal, or hit a timeout.

Exit causes and the effect of the Restart settings on them:

Restart settings/Exit causes no always on-success on-failure on-abnormal on-abort on-watchdog
Clean exit code or signal X X
Unclean exit code X X
Unclean signal X X X X
Timeout X X X
Watchdog X X X X

As exceptions to the setting above, the service will not be restarted if the exit code or signal is specified in RestartPreventExitStatus directive (see below) or the service is stopped with systemctl stop or an equivalent operation. Also, the services will always be restarted if the exit code or signal is specified in RestartForceExitStatus.

Note that service restart is subject to unit start rate limiting configured with StartLimitIntervalSec and StartLimitBurst directives, see systemd.unit(5) for details. A restarted service enters the failed state only after the start limits are reached.

Example

We have a tsm.service unit file, that start and manage tivoli storage manager service.

[Unit]
Description=IBM Tivoli Storage Manager Client dsmcad systemd-style sample service description
Documentation=http://www-01.ibm.com/support/knowledgecenter/SSGSG7_7.1.4/client/t_protect_wf.html?lang=en
After=local-fs.target network-online.target

[Service]
Type=forking
GuessMainPID=no
Environment="DSM_DIR=/opt/tivoli/tsm/client/ba/bin/"
Environment="DSM_CONFIG=/opt/tivoli/tsm/client/ba/bin/dsm.sys"
Environment="DSM_LOG=/var/log/tsm"
ExecStart=/opt/tivoli/tsm/client/ba/bin/dsmcad
Restart=always

[Install]
WantedBy=multi-user.target

Another parts of this guide:

SUBSCRIBE FOR NEW ARTICLES

@
comments powered by Disqus