sections in this module | City
College of San Francisco - CS260A Linux System Administration Module: StartupShutdown III |
module list |
systemd unit files
[ Note: the man pages for systemd are very good. You may want to look there for a companion to (or substitute for) this reading. See the man pages on systemd.unit, systemd.service and systemd.target for a start. They are only on RH7, of course. ]
Unit files
Now that we've seen the systemd is not so difficult, let's look at a unit file for the sshd service (a .service file)
and see if we can make sense of it.
System Unit files can be located in three places:
/etc/systemd/system contains local units and local dependencies. These have the highest priority when resolving dependencies. When a group of units is analyzed by systemd and dependencies are added (say x depends on y which depends on z, then x implicitly depends on z) the dependencies are placed here.
/run/systemd/system contains local dependencies created at runtime. (Sorry, I don't really understand this one.)
Since sshd is an installed service, its unit file should be in /usr/lib/systemd/system.
If you took the time to examine an upstart script on 6.5, this
format is familiar. The file contains three sections: a Unit section
and Install section, which are common to all unit files, and a Service
section, which is particular to service unit files. (The format is a
takeoff of [yes] Microsoft Windows .ini files.)
There are many other types of unit files besides service units. One we will encounter shortly is a target. Target units simply control other units, activating and deactivating them as a group. Unlike service units, which actually start a process, target units simply cause transitions or add dependencies.
Note: you can see from the example above the simple format of unit
files. Blank lines and lines that start with either a semi-colon (;) or
a hash mark (#) are ignored.
The Unit section describes the unit and its dependencies. There are a lot of options in this section. Let's go over the most important ones:
Option |
Meaning |
Description |
Free-form description string |
Documentation |
Where to go for documentation. In the example above, you're on your own |
Requires |
units that must be activated if
this one is. If a required unit fails or is deactivated, this unit will
be as well. Thus if unit y has Requires=x, unit y requires unit x. Additional requires dependencies may be encoded using symlinks in a directory named the same as the unit file with the extension .requires Thus for unit file x.service, the requires consist of its Requires= list plus those unit files that have symlinks in the directory x.service.requires (Note that there may be X.service.requires directories in all three locations for unit files.) |
Wants |
units that should be activated
if this one is. However, if they cant be activated, go ahead and
activate this unit anyway. Additional wants dependencies may be encoded
using symlinks in a .wants directory similar to Requires (above) |
Conflicts |
units
that cannot be active at the same time as this unit. If the conflicting
unit is active when this one is started, the conflicting unit is
stopped. If the conflicting unit is started while this one is active,
this unit will be stopped. |
After |
Before and After are very confusing (at least to me). To get them straight, prefix the word with Start me and delete the = sign. Thus After=xxx.service means Start me after xxx.service. Note that this does not mean that xxx.service will be started, but if it is started, this unit will not be started until after it is running. |
Before |
The current unit must be running before these can be started, if they are to be part of the running system. |
AllowIsolate |
If set to yes (the default is no), this unit may be used with the systemctl isolate
command. (Note, the documentation says the values for this option are
true and false, but the installed unit files have yes or no.) |
The wants and requires of unit X form a group of units that are activated when unit X is. The requires elements are required - the failure of a requires unit will cause the shutdown of unit X. The wants elements are not required, but at attempt should be made to activate them with unit X.
Before we go on, let's look again at the Unit section of our sample sshd.service:
This indicates that sshd should be started after syslog.target,
network.target and auditd.service, if those units are to be part of the running system.
The Install section
The Install section specifies how to install the unit. It is only
used during the install process, but it can specify additional
dependencies using two options Wantedby= and Requiredby=. If x.service
has a Wantedby=foo.service directive in its Install section, then a
symlink to x.service is created in a directory foo.service.wants,
creating a dependency identical to the appearance of a Wants=x.service
in the foo.service unit file.
That last paragraph was unclear, I'm sure. Suffice it to say that dependencies are complex because they can form a chain that is not obvious until systemd analyzes it. When a change in state is imminent, the dependencies must be satisfied correctly. To speed this up at runtime, as many of the dependencies as possible are stored in filesystem objects when the units are installed. Suppose unit Y is installed. In its unit file it encodes the units that it wants and knows must exist. There very well may be other units that are optional on the system that it would want if they exist but they are not encoded in the unit file since they are optional. Suppose unit X is such a unit - it would be wanted by unit Y if it existed. This want is added to unit Y by a WantedBy option in unit X. (sorry, you may have to read this paragraph a couple of times.)
The most common examples of this are the big system state targets: basic, multi-user and graphical. Let's take the example of multi-user.target. As you might expect, it wants a lot of stuff - everything that should be up at multi-user mode should be wanted by multi-user.target. But at installation, the file created for multi-user.target does not know what is installed - other than those units that are required for basic system functionality. Thus, its Wants (and Requires) are limited:
# grep -e Wants -e Requires multi-user.target
Requires=basic.target
Then, everything that should be started in multi-user mode should
have a unit file that indicates it is WantedBy multi-user.target
A couple of the ones that are in this list that we will recognize are rsyslog.service, NetworkManager.service, and sshd.service. To add a Want of their unit by multi-user.target a symlink is created in multi-user.target.wants that points to their service. (This symlink could be in a multi-user.target.wants directory in either /usr/lib/systemd/systemd or in /etc/systemd/system.) In fact, we find the symlinks in the latter location:
Now, you might think that there would be 74 symlinks since we found
74 instances of WantedBy=multi-user.target, but, due to
interdependencies between them, the actual number is less. Again, they
can be distributed between two locations:
# ls /etc/systemd/system/multi-user.target.wants | wc -l
35
# ls /usr/lib/systemd/system/multi-user.target.wants | wc -l
8
OK, believe it or not, that was a simple example - at least the simplest I could find. Suffice it to say that the dependency resolution is difficult. You cannot understand all the dependencies of a unit by simply looking at the unit file, even if you remember to look in the wants directories. Instead, use systemctl show
The Service section
Many of the specialized unit types have a section that is specific for their specialization. Thus, service units have a Service section that encodes how the service is to be started and managed. Before we cover the options in the Service section in general, let's return to our simple service, sshd, and look at its Service section:
[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStartPre=/usr/sbin/sshd-keygen
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
There are a lot of options in the Service section. We will only cover the most basic ones:
Variable |
Meaning |
Type |
How to manage the service. There are several alternatives - we will cover simple, forking and oneshot. simple is the default.
|
ExecStart |
The
command to run to start the
service. In the example above, $OPTIONS come from the EnvironmentFile,
that systemd reads to set internal variables for substitution or from
variables set in the Environment= directive. Note: this is not a shell
command! Specifically, redirection operators are not allowed. If you
want a shell command you must use a shell to interpret the command. An absolute path to the executable must be used. |
ExecStartPre ExecStartPost |
Commands to be run before and after ExecStart |
ExecReload ExecStop |
Commands to execute to reload the configuration of the service and to stop the service. |
Restart |
Whether
to restart the process if it exits. Some of the choices are no (the
default), on-failure, on-success, and always. This goes with the option
RestartSec= |
RestartSec |
How long to wait after the unit
exits until it is restarted, assuming Restart= is not set to no. The
unit value is secs, unless a suffix (min,msec,sec) is added. |
KillMode |
How to kill the unit. Choices
are none (just execute the ExecStop), process (kill the main process
only), control-group (kill all processes in the control group, the default) |
Scope units
scope units are similar to service units except they manage a set of processes that were started external to systemd - i.e., systemd does not start anything. An example is the desktop processes that are created for you at login to the GUI by gdm. These are placed in a separate automatically-created scope. Interested readers are referred to systemd.scope
Slice units
A slice is a new level of heirarchy inserted into the tree of
control groups as defined by a slice unit. They are used for
controlling huge groupings of systemd processes and provide the ability
to limit their resources as a group. You probably wont need to muck
with slices - there are four default ones created for you: the parent
slice, named - (yes, dash), the system slice, which contains all the
system cgroups, the user slice, which contains all user cgroups (such
as the processes created in a login session) and the machine slice,
which contains all virtual machines.
Other unit types
Other unit types are specialized and are usually resources used by services. These are:
mount, automount, swap |
filesystem control. mount units
control mount points; automount units control automount points, and
swap units control activation of swap devices |
timer, device, path |
these control activation of a
unit due to a timer event, a device access, or a path access. (Units
can be configured to be activated by touching these objects) |
socket |
also used for activation of a
unit, socket units also force the creation of sockets when a service
unit is started. If x.service is started and x.socket exists, the
socket described in x.socket is created and given to x.service when it
is started. |
for more information see the man page on systemd.x where x is the unit type.
Prev | This page was made entirely
with free software on linux: Kompozer, the Mozilla Project and Openoffice.org |
Next |