s6 is a collection of programs that can be used for service supervision. s6-rc is a service manager built on top of s6. Both are composed of multiple simple tools that can be used independently or with the rest of the suite.
s6-rc can be used to manage system service, user-session service, or an ad-hoc collection of services. s6 is equally flexible and can be used for any sort of service.
The official documentation does a good job of explaining every component in great details. This is a high level overview.
s6
s6
is a small suite of programs to supervise services (or really any other
type of process). Understanding this suite first helps understand s6-rc
later
on.
s6-log
s6-log
reads input from stdin and saves logs, handling storage and rotation.
Log rotation needs to be handled by the same process that writes logs; any separation between processes eventually leads to race conditions, requiring inter-process locks or other similar issues.
Generally, another service is executed piping its output to s6-log
. Service
processes themselves don’t ever need access to the log files.
Like most tools in this list, it can be used completely independently of the s6
suite. This implies, amongst other things, that it is easy to test s6-log
by
itself to get a better feeling of how it works.
The easiest usage of s6-log
is to pipe output from a process to it:
offlineimap 2>&1 | s6-log T /path/to/logs/offlineimap/
s6-log
takes an output directory, given that it will handles log rotation
inside that of it. It also keeps a lock to avoid concurrent instances writing to
the same directory.
s6-log
focuses on ensuring that all logs are saved and no messages are lost.
This causes frequent writes to disk and may not be ideal when the primary
storage is an SD card or some other device that wears out quickly with frequent
writes. Consider using logbookd
for scenario which require reduced writes
and losing logs in an acceptable compromise.
s6-supervise
s6-supervise
is the service supervisor program. It runs as direct parent
of a service process. It handles restarting the service when it dies,
terminating it (when explicitly requested), and notifies registered processed
when it is up or down.
The definition of a single service is represented by a directory called a service directory. For advanced configurations, it is possible to programmatically generate these directories. If you’re curious what these look like, I have a collection of service directories that I use for my desktop sessions.
A running s6-supervise
instance can be manually controlled via s6-svc
.
Much like s6-log
, s6-supervise
(together with s6-svc
) can be used
independently of the rest of the s6 suite. It is perfectly feasible to write or
adapt some other service manager and use s6-supervise
for service supervision
without using any other pieces of the s6
.
s6-svscan
s6-svscan
reads a scan directory; a directory with multiple service
directories. It then runs an instance of s6-supervise
for each one.
s6-svscan
is often the root of the service process tree.
s6-svscan
can be manually controlled via s6-svscanctl
.
s6-rc
s6-rc is a service manager. It is a collection of programas that builds on top of s6 and implements dependency management, bundles (these are similar to OpenRC runlevels) and one-shot services.
While s6-rc
sounds like the obvious choice to use on top of s6
, it is
perfectly feasible to use a separate service manager which uses s6
for service
supervision under the hood. An example of this is anopa.
s6-rc
doesn’t actually run the services itself; it delegates this to
s6-svscan
under the hood. s6-rc
merely mutates the scan directory, and
makes s6-svccan
reload, start, or stop services as needed. It also uses its
own “live” directory for its runtime data and state.
s6-rc-init
initialises the scan directory with all services disabled by
default. Further state changes (including starting up an initial set of
services) can be triggered via the s6-rc
command.
s6-rc
keeps its definitions in a compiled database, which must first be
generated using s6-rc-compile
. The compiled database is then re-usable, so it
is possible to keep versioned copies, as well as re-use the last-compiled
database after system reboots.
While compiling a database initially sounded like a tedious step at first, the
compilation step helps ensure that the directory used by s6-rc
contains valid
data before it is used. For example, when I accidentally added a non-existent
service as a dependency for another, compilation failed. This ensures that the
source directory can’t have completely bogus data (which could yield terrible
results after a reboot). It also prevents re-doing all the parsing work on each
start-up: it is done once by an individual tool and the pre-digested data is
loaded in subsequent runs.
I find this last trait an unusual approach, but it is a solid design choice.
Caveat: Note that the $SERVICENAME/log
pattern supported by s6-svscan
is
not supported by s6-rc
. Loggers must be declared via provider_for
and
consumer_for
.
Process tree
s6-svscan
is the parent of all s6-supervise
processes, and s6-supervise
process is the parent of a different service. This results in a process tree
that is intuitively quite intuitive to understand (ps auxf
will even render
this in a way that can be visually comprehended).
Readiness notification
Services supervised by s6-supervise
can implement service startup
notifications, often referred to as readiness notification.
This allows services to notify their supervisor when they are ready. While the
exact definition of ready varies for each service, this usually indicates that
the service is ready to accept client connections. For example, a service that
sets up a unix domain socket on which it listens to connections will only send a
readiness notification after the socket is ready to receive client connections.
Readiness notification allows ordering dependant service and having each one
start only when their dependency is ready. For example, darkman
will connect
to dbus
as soon as it starts, so darkman
needs to be started after dbus
is
ready. Starting darkman
after dbus has merely started will inevitably lead
to race conditions where darkman
tries to connect to dbus
before the latter
has set up its socket.
Usage via wrappers
Personally, I find that using the s6 utilities directly tends be too low level. Most of my usage so far has been using own wrapper scripts. I expect that other high-level tools will show up over time, and the components mentioned above will likely not be used directly by most users.
See also
- As mentioned above: the official documentation is well detailed, albeit a bit terse and it takes a while to figure out how to navigate it properly.
- The same documentation is available (from a third party) as man pages. These
are also available in the alpine repositories as
s6-man-pages
ands6-rc-man-pages
. I do wish that upstream would focus on man pages first, and then use those as a base for the HTML pages. - The gentoo wiki has an s6 article with further information.
There are numerous additional utilities in the s6 and s6-rc suites. It’s worth getting to know the basics of most of them.