[git commit] README_distro_proposal.txt: writeup about runit adoption

Denys Vlasenko vda.linux at googlemail.com
Sat Dec 3 13:06:55 UTC 2016

commit: https://git.busybox.net/busybox/commit/?id=fdb4421e00cc5115cffb55aac79c709a3a5108dd
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
 examples/var_service/README_distro_proposal.txt | 291 ++++++++++++++++++++++++
 1 file changed, 291 insertions(+)

diff --git a/examples/var_service/README_distro_proposal.txt b/examples/var_service/README_distro_proposal.txt
new file mode 100644
index 0000000..9b3fe04
--- /dev/null
+++ b/examples/var_service/README_distro_proposal.txt
@@ -0,0 +1,291 @@
+	A distro which already uses runit
+I installed Void Linux, in order to see what do they have.
+Xfce desktop looks fairly okay, network is up.
+ps tells me they did put X, dbus, NM and udev into runsvdir-supervised tree:
+    1 ?        00:00:01 runit
+  623 ?        00:00:00   runsvdir
+  629 ?        00:00:00     runsv
+  650 tty1     00:00:00       agetty
+  630 ?        00:00:00     runsv
+  644 ?        00:00:09       NetworkManager
+ 1737 ?        00:00:00         dhclient
+  631 ?        00:00:00     runsv
+  639 tty4     00:00:00       agetty
+  632 ?        00:00:00     runsv
+  640 ?        00:00:00       sshd
+ 1804 ?        00:00:00         sshd
+ 1809 pts/3    00:00:00           sh
+ 1818 pts/3    00:00:00             ps
+  633 ?        00:00:00     runsv
+  637 tty5     00:00:00       agetty
+  634 ?        00:00:00     runsv
+  796 ?        00:00:00       dhclient
+  635 ?        00:00:00     runsv
+  649 ?        00:00:00       uuidd
+  636 ?        00:00:00     runsv
+  647 ?        00:00:00       acpid
+  638 ?        00:00:00     runsv
+  652 ?        00:00:00       console-kit-dae
+  641 ?        00:00:00     runsv
+  651 tty6     00:00:00       agetty
+  642 ?        00:00:00     runsv
+  660 tty2     00:00:00       agetty
+  643 ?        00:00:00     runsv
+  657 ?        00:00:02       dbus-daemon
+  645 ?        00:00:00     runsv
+  658 ?        00:00:00       cgmanager
+  648 ?        00:00:00     runsv
+  656 tty3     00:00:00       agetty
+  653 ?        00:00:00     runsv
+  655 ?        00:00:00       lxdm-binary
+  698 tty7     00:00:14         Xorg
+  729 ?        00:00:00         lxdm-session
+  956 ?        00:00:00           sh
+  982 ?        00:00:00             xfce4-session
+ 1006 ?        00:00:04               nm-applet
+  654 ?        00:00:00     runsv
+  659 ?        00:00:00       udevd
+Here is a link to Vod Linux's wiki:
+    https://wiki.voidlinux.eu/Runit
+Void Linux packages install their services as subdirectories of /etc/rc,
+such as /etc/sv/sshd, with a script file, "run", and a link
+"supervise" -> /run/runit/supervise.sshd
+For sshd, "run" contains:
+    #!/bin/sh
+    ssh-keygen -A >/dev/null 2>&1 # generate host keys if they don't exist
+    [ -r conf ] && . ./conf
+    exec /usr/bin/sshd -D $OPTS
+That's it from the POV of the packager.
+This is pretty minimalistic, and yet, it is already distro-specific:
+the link to /run/runit/* is conceptually wrong, it requires packagers
+to know that /etc/rc should not be mutable and thus they need to use
+a different location in filesystem for supervise/ directory.
+I think a good thing would be to require just one file: the "run" script.
+The rest should be handled by distro tooling, not by packager.
+A similar issue is arising with logging. It would be ideal if packagers
+would not need to know how a particular distro manages logs.
+Whatever their daemons print to stdout/stderr, should be automagically logged
+in a way distro prefers.
+* * * * * * * *
+	Proposed "standard" on how distros should use runit
+The original idea of services-as-directories belongs to D.J.Bernstein (djb),
+and his project to implement it is daemontools: https://cr.yp.to/daemontools.html
+There are several reimplementations of daemontools:
+- runit: by Gerrit Pape, http://smarden.org/runit/
+  (busybox has it included)
+- s6: by Laurent Bercot, http://skarnet.org/software/s6/
+It is not required that a specific clone should be used. Let evolution work.
+	Terminology
+daemon: any long running background program. Common examples are sshd, getty,
+ntpd, dhcp client...
+service: same as "daemon"
+service directory: a directory with an executable file (script) named "run"
+which (usually) execs daemon (possibly after some preparatory steps).
+It should start it not as a child or daemonized process, but by exec'ing it
+(inheriting the same PID and the place in the process tree).
+service monitor: a tool which watches a set of service directories.
+In daemontools package, it is called "svscan". In runit, it is called
+"runsvdir". In s6, it is called "s6-svscan".
+Service monitor starts a supervisor for each service directory.
+If it dies, it restarts it. If service directory disappears,
+service monitor will not be restarted if it dies.
+runit's service monitor (runsvdir) sends SIGTERM to supervisors
+whose directories disappeared.
+supervisor: a tool which monitors one service directory.
+It runs "run" script as its child. It restarts it if it dies.
+It can be instructed to start/top/signal its child.
+In daemontools package, it is called "supervise". In runit, it is called
+"runsv". In s6, it is called "s6-supervise".
+Conceptually, a daemontools clone can be designed such that it does not *have*
+the supervisor component: service monitor can directly monitor all its daemons
+(for example, this may be a good idea for memory-constrained systems).
+However all three existing projects (daemontools/runit/s6) do have a per-service
+supervisor process.
+log service: a service which is exclusively tasked with logging
+the output of another service. It is implemented as log/ subdirectory
+in a service directory. It has the same structure as "normal"
+service dirs: it has a "run" script which starts a logging tool.
+If log service exists, stdout of its "main" service is piped
+to log service. Stops/restarts of either of them do not sever the pipe
+between them.
+If log service exists, daemontools and s6 run a pair of supervisors
+(one for the daemon, one for the logger); runit runs only one supervisor
+per service, which is handling both of them (presumably this is done
+to use fewer processes and thus, fewer resources).
+	User API
+"Users" of service monitoring are authors of software which has daemons.
+They need to package their daemons to be installed as services at package
+install time. And they need to do this for many distros.
+The less distros diverge, the easier users' lives are.
+System-wide service dirs reside in a distro-specific location.
+The recommended location is /var/service. (However, since it is not
+a mandatory location, avoid depending on it in your run scripts).
+The install location for service dirs is /etc/rc:
+when e.g. ntpd daemon is installed, it creates the /etc/rc/ntpd
+directory with (minimally) one executable file (script) named "run"
+which starts ntpd daemon. It can have other files there.
+At boot, distro should copy /etc/rc/* to a suitable writable
+directory (common choice are /var/service, /run/service etc).
+It should create log/ directories in each subdirectory
+and create "run" files in them with suitable (for this particular distro)
+logging tool invocation, unless this directory chose to channel
+all logging from all daemons through service monitor process
+and log all of them into one file/database/whatever,
+in which case log/ directories should not be created.
+It is allowable for a distro to directly use /etc/rc/ as the only
+location of its service directories. (For example,
+/var/service may be a symlink to /etc/rc).
+However, it poses some problems:
+(1) Supervision tools will need to write to subdirectories:
+the control of running daemons is implemented via some files and fifos
+in automatically created supervise/ subdirectory in each /etc/rc/DIR.
+(2) Creation of a new service can race with the rescanning of /etc/rc/
+by service monitor: service monitor may see a directory with only some files
+present. If it attempts to start the service in this state, all sorts
+of bad things may happen. This may be worked around by various
+heuristics in service monitor which give new service a few seconds
+of "grace time" to be fully populated; but this is not yet
+implemented in any of three packages.
+Daemons' output file descriptors are handled somewhat awkwardly
+by various daemontools implementations. For example, for runit tools,
+daemons' stdout goes to wherever runsdir's stdout was directied;
+stderr goes to runsvdir, which in turn "rotates" it on its command line
+(which is visible in ps output).
+Hopefully this get changed/standardized; while it is not, the "run" file
+should start with a
+    exec 2>&1
+command, making stderr equivalent to stdout.
+An especially primitive service which does not want its output to be logged
+with standard tools can do
+    exec >LOGFILE 2>&1
+or even
+    exec >/dev/null 2>&1
+To prevent creation of distro-specific log/ directory, a service directory
+in /etc/rc can contain an empty "log" file.
+	Controlling daemons
+The "svc" tool is available for admins and scripts to control services.
+In particular, often one service needs to control another:
+e.g. ifplugd can detect that the network cable was just plugged in,
+and it needs to (re)start DHCP service for this network device.
+The name of this tool is not standard either, which is an obvious problem.
+I propose to fix this by implementing a tool with fixed name and API by all
+daemontools clones. Lets use original daemontools name and API. Thus:
+The following form must work:
+	svc -udopchaitkx DIR
+Options map to up/down/once/STOP/CONT/HUP/ALRM/INT/TERM/KILL/exit
+commands to the daemon being controlled.
+The form with one option letter must work. If multiple-option form
+is supported, there is no guarantee in which order they take effect:
+svc -it DIR can deliver TERM and INT in any order.
+If more than one DIR can be specified (which is not a requirement),
+there is no guarantee in which order commands are sent to them.
+If DIR has no slash and is not "." or "..", it is assumed to be
+relative to the system-wide service directory.
+The "svok DIR" tool exits 0 if service is running, and nonzero if not.
+The "svstat DIR1 DIR2..." prints one human-readable line for each directory,
+saying whether supervise is successfully running in that directory,
+and reporting the status information maintained by supervise.
+Other tools with different names and APIs may exist; however
+for portability scripts should use the above tools.
+Creation of a new service on a running system should be done atomically.
+To this end, first create and populate a new /etc/rc/DIR.
+Then "activate" it by running ??????? - this copies (or symlinks,
+depending on the distro) its files to the "live" service directory,
+whereever it is located on this distro.
+Removal of the service should be done as follows:
+svc -d DIR [DIR/log], then remove the service directory
+(this makes service monitor SIGTERM per-directory supervisors
+(if they exist in the implementation))
+	Implementation details
+Top-level service monitor program name is not standardized.
+[svscan, runsvdir, s6-svscan ...]
+It may run one per-directory supervisor, or two supervisors
+(one for DIR/ and one for DIR/log/); for memory-constrained systems
+an implementation is possible which itself controls all services, without
+intermediate supervisors.
+[runsvdir runs one "runsv DIR" per DIR, runsv handles DIR/log/ if that exists]
+[svscan runs a pair of "superwise DIR" and "superwise DIR/log"]
+Directores are remembered by device+inode numbers, not names. Renaming a directory
+does not affect the running service (unless it is renamed to a .dotdir).
+Removal (or .dotdiring) of a directory sends SIGTERM to any running services.
+Standard output of non-logged services goes to standard output of service monitor.
+Standard output of logger services goes to standard output of service monitor.
+Standard error of them always goes to standard error of service monitor.
+If you want to log standard error of your logged service along with its stdout, use
+"exec 2>&1" in the beginning of your "run" script.
+Whether stdout/stderr of service monitor is discarded (>/dev/null)
+or logged in some way is system-dependent.
+	Containers
+[What do containers need?]

More information about the busybox-cvs mailing list