s6-linux-init
Software
skarnet.org
Quickstart and FAQ for s6-linux-init
Quickstart
- Install all the s6-linux-init dependencies:
- Install s6-linux-init itself.
- Save your old /sbin/init binary.
- Save and remove your old /etc/s6-linux-init directory, if you have one.
- Make sure you have a /run directory.
- Write a machine initialization script in /etc/rc.init and
a machine shutdown script in /etc/rc.shutdown. Make sure they are
executable. See below for more information on how to write these scripts.
- Check that your devtmpfs is automounted by your kernel at boot time. If it is not,
add the -d 1 option to the s6-linux-init-maker command line below.
- As root, run:
rm -rf /tmp/s6-linux-init /tmp/init
s6-linux-init-maker /tmp/s6-linux-init
mv /tmp/s6-linux-init /etc/
ln -sf /etc/s6-linux-init/init /sbin/init
- Reboot.
- Congratulations! your machine is now running a s6-based init system.
- To shut the machine down, use the
s6-halt,
s6-poweroff or
s6-reboot command as appropriate.
What should go into /etc/rc.init and /etc/rc.shutdown ?
/etc/rc.init
This script will be run after s6-linux-init has done is job, i.e.
s6-svscan is running as process 1, and it
is now up to /etc/rc.init to get the machine to its usable state.
It normally contains a call to the service manager to bring up all the services;
for instance, if you're using
s6-rc as your service manager, and
your top bundle (containing all the services you want to bring up) is named
ok-all, a proper /etc/rc.init could look like this:
#!/bin/sh
s6-rc-init /run/service && exec s6-rc -u change ok-all
The script can assume that:
- There is a tmpfs partition, only writable by root, mounted on /run
- There is a s6 supervision tree
running on /run/service
- /dev is mounted, but /proc and /sys are not
/etc/rc.shutdown
This script is spawned by s6-svscan
when the administrator calls s6-halt,
s6-poweroff or
s6-reboot. When this script exits, the final
shutdown sequence is run, which means that the supervision tree is dismantled,
all processes are killed, the file systems are umounted and the system
undergoes a hardware shutdown or reboot. So the goal of this script is to
bring services down in an orderly fashion and perform all the necessary
cleanups before all remaining processes are summarily killed.
If you're using s6-rc as your
service manager, a proper /etc/rc.shutdown could look like this:
#!/bin/sh
exec s6-rc -da change
FAQ
Why is it so complicated to use s6 as an init process? It's much
simpler with runit.
Yes, runit is simpler, because it provides a simple
runit binary
suitable as a /sbin/init program and calls scripts to
handle the three stages of init. However, the runit design has a
few perfectible points:
- The one-time initialization is performed in /etc/runit/1, but
the supervision tree is not run until /etc/runit/2, which means
means that it is impossible to start supervised services during the
one-time initialization. Early daemons such as udevd, for
instance, have to remain unsupervised.
- runit runs with its descriptors pointing to /dev/console,
which means that error messages from the supervision tree, and uncaught
logs, will be displayed on the system console; they are not saved beyond
the console buffer capabilities.
- The runit supervision tree is of height 3
(runit, runsvdir, runsv), when height 2 is enough - some init
systems, like sysvinit, systemd or launchd, even provide a
supervision tree of height 1! (At the expense of complexity in the init
process, of course.) Height 3 is a bit redundant, because the supervision
capabilities of the root will be redundant with either those of the trunk
or those of the branches. Its display is also aesthetically less pleasing than
height 2: try out ps afuxww on a runit-based system.
Yes, this point is extremely minor, but still deserves a mention. :-)
Running a s6-based init addresses those issues:
- Save for the initial tmpfs mount, all of the machine
initialization runs in the stage 2 script, i.e. /etc/rc.init,
and the supervision tree is already available at that point. This
makes it possible to start one-shot services as well as long-run
services in the desired order while ensuring that every long-run service
is properly supervised, i.e. it lays the ground for a proper dependency
management system.
- s6-linux-init solves the problem of uncaught logs in a clean
way, and any error message from any process in the system is
guaranteed to end up in a logging directory. The only
exception is error messages from the catch-all logger process itself:
those naturally go to /dev/console.
- When s6-svscan runs as process 1, the supervision tree is of
height 2, and ps afuxww looks clean.
To sum up, a s6-based init is cleaner than a runit-based
init; it's a bit more complex to set up, but it organizes the system
in a better way, without using more resources. And the goal of
s6-linux-init is to make the setup more accessible.
My /etc/rc.init script is not printing anything!
You probably gave the -r option to
s6-linux-init-maker, and
your /etc/rc.init's output is being logged into the
/run/uncaught-logs directory instead of printed to
/dev/console.
I want to run s6 in a container, and I just want to log
to stdout/stderr, without this tmpfs and /dev/console
stuff and
without having a catch-all logger inside the container. Is it
possible ?
Yes, it is possible, but then s6-linux-init may not be what you
are looking for. For your case, it will be simpler to run s6-svscan
directly!
If you are using
Docker, there is a
s6-overlay
project specifically made for integrating s6 into Docker images.