[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Systemd services (was Re: If Linux Is About Choice, Why Then ...)



On Mon, Apr 03, 2017 at 09:36:16AM -0500, Tom Browder wrote:
> But I kind of understand why systemd, but I wish I could find a good
> cookbook description of how to add or modify a new process.

The first hurdle is learning the terminology that systemd uses.  It's
not exactly intuitive.

Systemd has "run levels" which are used to control which groups of
services are started at boot time.  But it calls these things "targets"
instead of "run levels".

The default target is called "graphical.target", which means that if
a Display Manager is installed and enabled, it will be started.  This
is analogous to run level 5 on Red Hat systems.

You can see your system's default target by running this command:

$ systemctl get-default

The other target (run level) that most people will care about is called
"multi-user.target".  This is analogous to run level 3 on Red Hat
systems.  It's the same as "graphical.target" but without the Display
Manager.

If you want to change your system's "run level" from graphical.target
to multi-user.target, run this command as root:

# systemctl set-default multi-user.target

To see a list of your available targets (assuming no major local changes),
use this command:

$ find /lib/systemd/ -name '*.target'

Now, the trickier part: adding a new managed service.  Systemd calls
these things "units".  It also calls them "services", which are a
specific type of unit.

In the typical case, where you just want to run a daemon, nothing fancy,
what you do is create a file in the directory /etc/systemd/system.
This file's name should end with ".service" to indicate that this is a
service.  The first part of the file's name should be whatever you want
your service to be called.

The .service file is a text file in the "Windows INI" format,
meaning there are sections with [Headers] in square brackets, and
configuration lines within each section.  (See "man systemd.unit" and
"man systemd.service" for full details.)

Suppose you want to start DJB's daemontools from a locally created
systemd unit/service.  Here's a file that will do that:

======================================================================
[Unit]
Description=daemontools supervisor
After=getty.target

[Service]
Type=simple
User=root
Group=root
Restart=always
ExecStart=/command/svscanboot /dev/ttyS0
TimeoutSec=0

[Install]
WantedBy=multi-user.target
======================================================================

Mostly it's quite simple once you have an example like this.
The ExecStart= line gives the command to be executed.  The Type=
line tells us that this command runs in the foreground, which
every sane daemon should do.  If your daemon is self-backgrounding,
look for an option to tell it to STOP THAT, BAD DAEMON.  Anything
that has been seriously maintained at some time in this millennium
should either run in the foreground by default, or should at least
have an option to run in the foreground.

I cannot stress this enough.  Your daemons should run in the foreground.
Self-backgrounding is BAD.  Unconditional self-backgrounding is grounds
for being deleted and replaced by something that does not suck.

However, because systemd has to live in a world where evil runs free,
it goes out of its way to be accomodating to those who must live
under such a horrible regime.  Therefore, it can be told to manage
even a self-backgrounding daemon.  (The Linux kernel introduced an
entirely new thing called a "cgroup" to make this possible.  That's
how ridiculous self-backgrounding is.)

If your daemon was written in 1985 and self-backgrounds and can't be
changed, and you don't have the time to rewrite it yourself, then read
"man systemd.service" and look for the word "forking".  Be sure to read
all of the recommendations.

Once you've written your .service file, given it a cool name, and saved
it in /etc/systemd/system, there are three more steps.

First, you run this command to tell systemd to look for new unit files
(as root):

# systemctl daemon-reload

Second, you tell systemd that your service should be enabled, which
means it gets started automatically at boot time.  Again, as root:

# systemctl enable your.service

Finally, tell systemd to start the service right now:

# systemctl start your.service

When you run systemctl start (or any other systemctl subcommand), note
that all it does is send a message to systemd, asking systemd to do
stuff.  It doesn't hang around to see what happened.  It doesn't report
status.  It just sends the message.

Some people dislike this.  They want to see a reassuring message to tell
them that yes, their daemon is actually running now.  Usually because
sysvinit used to do that for them.

Since there's no feedback from systemctl, therefore, there's one more
command you should learn.  You can run it without root:

$ systemctl status your.service

This shows you whether things are running or not.  In fact, it tells
you a whole bunch of stuff: the state of the service, how long it has
been in this state, where it loaded the definitions from, which
processes are part of the service's cgroup (in case there's more than
one), and so on.

In most cases, you can shorten "your.service" to simply "your".
For example, using a common, standard Debian service:

$ systemctl status cron
* cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled)
   Active: active (running) since Mon 2017-03-13 08:38:05 EDT; 3 weeks 0 days ago
     Docs: man:cron(8)
 Main PID: 492 (cron)
   CGroup: /system.slice/cron.service
           `-492 /usr/sbin/cron -f

Or using the locally installed daemontools service shown previously:

$ systemctl status daemontools.service
* daemontools.service - daemontools supervisor
   Loaded: loaded (/etc/systemd/system/daemontools.service; enabled)
   Active: active (running) since Wed 2017-01-11 03:28:47 EST; 2 months 21 days ago
 Main PID: 529 (svscanboot)
   CGroup: /system.slice/daemontools.service
           |-  529 /bin/sh /command/svscanboot /dev/ttyS0
           |-  531 svscan /service
           |-  532 readproctitle service errors: ...............................
           |-  533 supervise qmail-send
           |-  534 supervise log
           |-  535 supervise qmail-deliverabled
           |-  536 supervise log
           |-  537 supervise qpsmtpd
           |-  538 supervise log
           |-  539 /usr/local/bin/tcpserver -c 10 -v -R -p -u 112 -g 118 0 25...
           |-  540 /usr/local/bin/multilog t /var/log/qmail-deliverabled
           |-  541 /usr/local/bin/multilog t s5000000 /var/log/qpsmtpd
           |-  542 /usr/local/bin/qmail-deliverabled yes=4799(81.5%), no=1089...
           |-  543 qmail-send
           |-  544 /usr/local/bin/multilog t /var/log/qmail
           |-  550 qmail-lspawn ./Maildir/
           |-  551 qmail-rspawn
           |-  552 qmail-clean
           `-26226 /usr/local/bin/qpsmtpd [91.200.12.166 : [91.200.12.166] : ...

That's how you add a new service.

Now, let's suppose you want to MODIFY an existing service, one that is
provided by Debian.

The Debian service definitions will be in /lib/systemd/system/ (probably),
but you should NOT edit those files directly.  Your edits would be lost
when a new version of the package is installed.

What you do instead is, again, create a file in /etc/systemd/system.
But don't just copy the entire file over from /lib.  Rather, put a
few lines in it, indicating the specific things you want to override.
You're creating a little miniature "Windows INI" format file, with a
section header, and configuration line(s) underneath that.

Or, the fancy way to do it is to create a new DIRECTORY in
/etc/systemd/system with one or more files inside it, each of which
is one of these little miniature INI files to override one specific
thing.

For example, if you want to change the behavior of the Debian default
getty@ service to make it stop clearing the screen all the damned time,
you can do this:

# mkdir /etc/systemd/system/getty@.service.d
# vi /etc/systemd/system/getty@.service.d/noclear.conf

And in that file, you put these two lines:

[Service]
TTYVTDisallocate=no

This overrides the "TTYVTDisallocate=yes" that Debian placed in its
/lib/systemd/system/getty@.service file, which is what causes the
console to be cleared every time getty restarts.


Reply to: