s6-rc
Software
skarnet.org

Why s6-rc ?

The limits of supervision suites

Supervision suites such as s6, runit, perp or daemontools define a service as a long-lived process, a.k.a daemon. They provide tools to run the daemon in a reproducible way in a controlled environment and keep it alive if it dies; they also provide daemon management tools to, among others, send signals to the daemon without knowing its PID. They can control individual long-lived processes perfectly well, and s6 also provides tools to manage a whole supervision tree. To any system administrator concerned about reliability, supervision suites are a good thing.

However, a supervision suite is not a service manager.

Relying on a supervision suite to handle all the service management is doable on simple systems, where there aren't many dependencies, and where most of the one-time initialization can take place in stage 1, before any daemons are launched. On some embedded systems, for instance, this is perfectly reasonable.

On other systems, though, it is more problematic. Here are a few issues encountered:

To manage complex systems, pure supervision suites are insufficient, and real service managers, starting and stopping services in the proper order and handling both oneshots (one-time initialization scripts) and longruns (daemons), are needed.

Previous alternatives

Unix distributions usually come with their own init systems and service managers; all of those have flaws one way or another. No widely spread init system gets things right, which is the main reason for the recent "init wars" - no matter what init system you talk about, there are strong, valid reasons to like it and support it, and there are also strong, valid reasons to dislike it.

Non-supervision init systems usually fall in one of two categories, both with pros and cons.

Traditional, sequential starters

Those are either the historical Unix init systems, or newer systems that still favor simplicity. Among them, for instance:

All these systems run sequentially: they will start services, either oneshots or longruns, one by one, even when the dependency graph says that some services could be started in parallel. Also, the daemons they start are always unsupervised, even when the underlying init system provides supervision features. There usually is no readiness notification support on daemons either, daemons are fire-and-forget (but that's more on the scripts themselves than on the frameworks). Another common criticism of those systems is that the amount of shell scripting is so huge that it has a significant performance impact.

(Note that OpenRC has an option to start services in parallel, but at the time of this writing, it uses polling on a lock file to check whether a service has completed all its dependencies; this is heavily prone to race conditions, and is not the correct mechanism to ensure proper service ordering, so this option cannot be considered reliable.)

Another, less obvious, but important drawback is that service-launching scripts run as scions of the shell that invoked the command, and so they may exhibit different behaviours when they're run automatically at boot time and when they're run manually by an admin, because the environment is different. Scripts usually try to run in a clean environment, but it's hard to think of everything (open file descriptors!) and every script must protect itself with a gigantic boilerplate, which adds to the inefficiency problem.

Monolithic init behemoths

The other category of service managers is made of attempts to cover the flaws of traditional service starters, and provide supervision, dependency management and sometimes readiness notification, while reducing the amount of scripting needed. Unfortunately, the results are tightly integrated, monolithic init systems straying far away from Unix core principles, with design flaws that make the historical inits' design flaws look like a joke.

The problem of integrated init systems is that:

Pages and pages could be - and have been - written about the shortcomings of integrated init systems, but one fact remains: they are not a satisfying solution to the problem of service management under Unix.

The best of both worlds

s6-rc aims to be such a solution: it is small and modular, but offers full functionality. Parallel service startup and shutdown with correct dependency management (none of the systemd nonsense where services are started before their dependencies are met), correct readiness notification support, reproducible script execution, and short code paths.

The combination of s6 and s6-rc makes a complete, full-featured and performant init system and service manager, with probably the lowest total memory footprint of any service manager out there, and all the reliability and ease of administration that a supervision suite can provide. It is a real, viable alternative to integrated init behemoths, providing equivalent functionality while being much smaller and much more maintainable.