README_distro_proposal.txt 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. A distro which already uses runit
  2. I installed Void Linux, in order to see what do they have.
  3. Xfce desktop looks fairly okay, network is up.
  4. ps tells me they did put X, dbus, NM and udev into runsvdir-supervised tree:
  5. 1 ? 00:00:01 runit
  6. 623 ? 00:00:00 runsvdir
  7. 629 ? 00:00:00 runsv
  8. 650 tty1 00:00:00 agetty
  9. 630 ? 00:00:00 runsv
  10. 644 ? 00:00:09 NetworkManager
  11. 1737 ? 00:00:00 dhclient
  12. 631 ? 00:00:00 runsv
  13. 639 tty4 00:00:00 agetty
  14. 632 ? 00:00:00 runsv
  15. 640 ? 00:00:00 sshd
  16. 1804 ? 00:00:00 sshd
  17. 1809 pts/3 00:00:00 sh
  18. 1818 pts/3 00:00:00 ps
  19. 633 ? 00:00:00 runsv
  20. 637 tty5 00:00:00 agetty
  21. 634 ? 00:00:00 runsv
  22. 796 ? 00:00:00 dhclient
  23. 635 ? 00:00:00 runsv
  24. 649 ? 00:00:00 uuidd
  25. 636 ? 00:00:00 runsv
  26. 647 ? 00:00:00 acpid
  27. 638 ? 00:00:00 runsv
  28. 652 ? 00:00:00 console-kit-dae
  29. 641 ? 00:00:00 runsv
  30. 651 tty6 00:00:00 agetty
  31. 642 ? 00:00:00 runsv
  32. 660 tty2 00:00:00 agetty
  33. 643 ? 00:00:00 runsv
  34. 657 ? 00:00:02 dbus-daemon
  35. 645 ? 00:00:00 runsv
  36. 658 ? 00:00:00 cgmanager
  37. 648 ? 00:00:00 runsv
  38. 656 tty3 00:00:00 agetty
  39. 653 ? 00:00:00 runsv
  40. 655 ? 00:00:00 lxdm-binary
  41. 698 tty7 00:00:14 Xorg
  42. 729 ? 00:00:00 lxdm-session
  43. 956 ? 00:00:00 sh
  44. 982 ? 00:00:00 xfce4-session
  45. 1006 ? 00:00:04 nm-applet
  46. 654 ? 00:00:00 runsv
  47. 659 ? 00:00:00 udevd
  48. Here is a link to Void Linux's wiki:
  49. https://wiki.voidlinux.eu/Runit
  50. Void Linux packages install their services as subdirectories of /etc/rc,
  51. such as /etc/sv/sshd, with a script file, "run", and a link
  52. "supervise" -> /run/runit/supervise.sshd
  53. For sshd, "run" contains:
  54. #!/bin/sh
  55. ssh-keygen -A >/dev/null 2>&1 # generate host keys if they don't exist
  56. [ -r conf ] && . ./conf
  57. exec /usr/bin/sshd -D $OPTS
  58. That's it from the POV of the packager.
  59. This is pretty minimalistic, and yet, it is already distro-specific:
  60. the link to /run/runit/* is conceptually wrong, it requires packagers
  61. to know that /etc/rc should not be mutable and thus they need to use
  62. a different location in filesystem for supervise/ directory.
  63. I think a good thing would be to require just one file: the "run" script.
  64. The rest should be handled by distro tooling, not by packager.
  65. A similar issue is arising with logging. It would be ideal if packagers
  66. would not need to know how a particular distro manages logs.
  67. Whatever their daemons print to stdout/stderr, should be automagically logged
  68. in a way distro prefers.
  69. * * * * * * * *
  70. Proposed "standard" on how distros should use runit
  71. The original idea of services-as-directories belongs to D.J.Bernstein (djb),
  72. and his project to implement it is daemontools: https://cr.yp.to/daemontools.html
  73. There are several reimplementations of daemontools:
  74. - runit: by Gerrit Pape, http://smarden.org/runit/
  75. (busybox has it included)
  76. - s6: by Laurent Bercot, http://skarnet.org/software/s6/
  77. It is not required that a specific clone should be used. Let evolution work.
  78. Terminology
  79. daemon: any long running background program. Common examples are sshd, getty,
  80. ntpd, dhcp client...
  81. service: daemon controlled by a service monitor.
  82. service directory: a directory with an executable file (script) named "run"
  83. which (usually) execs some daemon, possibly after some preparatory steps.
  84. It should start it not as a child or daemonized process, but by exec'ing it
  85. (inheriting the same PID and the place in the process tree).
  86. service monitor: a tool which watches a set of service directories.
  87. In daemontools package, it is called "svscan". In runit, it is called
  88. "runsvdir". In s6, it is called "s6-svscan".
  89. Service monitor starts a supervisor for each service directory.
  90. If it dies, it restarts it. If service directory disappears,
  91. service monitor will not be restarted if it dies.
  92. runit's service monitor (runsvdir) sends SIGTERM to supervisors
  93. whose directories disappeared.
  94. supervisor: a tool which monitors one service directory.
  95. It runs "run" script as its child. It restarts it if it dies.
  96. It can be instructed to start/stop/signal its child.
  97. In daemontools package, it is called "supervise". In runit, it is called
  98. "runsv". In s6, it is called "s6-supervise".
  99. Conceptually, a daemontools clone can be designed such that it does not *have*
  100. the supervisor component: service monitor can directly monitor all its daemons
  101. (for example, this may be a good idea for memory-constrained systems).
  102. However all three existing projects (daemontools/runit/s6) do have a per-service
  103. supervisor process.
  104. log service: a service which is exclusively tasked with logging
  105. the output of another service. It is implemented as log/ subdirectory
  106. in a service directory. It has the same structure as "normal"
  107. service dirs: it has a "run" script which starts a logging tool.
  108. If log service exists, stdout of its "main" service is piped
  109. to log service. Stops/restarts of either of them do not sever the pipe
  110. between them.
  111. If log service exists, daemontools and s6 run a pair of supervisors
  112. (one for the daemon, one for the logger); runit runs only one supervisor
  113. per service, which is handling both of them (presumably this is done
  114. to use fewer processes and thus, fewer resources).
  115. User API
  116. "Users" of service monitoring are authors of software which has daemons.
  117. They need to package their daemons to be installed as services at package
  118. install time. And they need to do this for many distros.
  119. The less distros diverge, the easier users' lives are.
  120. System-wide service dirs reside in a distro-specific location.
  121. The recommended location is /var/service. (However, since it is not
  122. a mandatory location, avoid depending on it in your run scripts.
  123. Void Linux wanted to have it somewhere in /run/*, and they solved this
  124. by making /var/service a symlink).
  125. The install location for service dirs is /etc/rc:
  126. when e.g. ntpd daemon is installed, it creates the /etc/rc/ntpd
  127. directory with (minimally) one executable file (script) named "run"
  128. which starts ntpd daemon. It can have other files there.
  129. At boot, distro should copy /etc/rc/* to a suitable writable
  130. directory (common choice are /var/service, /run/service etc).
  131. It should create log/ directories in each subdirectory
  132. and create "run" files in them with suitable (for this particular distro)
  133. logging tool invocation, unless this directory chose to channel
  134. all logging from all daemons through service monitor process
  135. and log all of them into one file/database/whatever,
  136. in which case log/ directories should not be created.
  137. It is allowable for a distro to directly use /etc/rc/ as the only
  138. location of its service directories. (For example,
  139. /var/service may be a symlink to /etc/rc).
  140. However, it poses some problems:
  141. (1) Supervision tools will need to write to subdirectories:
  142. the control of running daemons is implemented via some files and fifos
  143. in automatically created supervise/ subdirectory in each /etc/rc/DIR.
  144. (2) Creation of a new service can race with the rescanning of /etc/rc/
  145. by service monitor: service monitor may see a directory with only some files
  146. present. If it attempts to start the service in this state, all sorts
  147. of bad things may happen. This may be worked around by various
  148. heuristics in service monitor which give new service a few seconds
  149. of "grace time" to be fully populated; but this is not yet
  150. implemented in any of three packages.
  151. This also may be worked around by creating a .dotdir (a directory
  152. whose name starts with a dot), populating it, and then renaming;
  153. but packaging tools usually do not have an option to do this
  154. automatically - additional install scripting in packages will be needed.
  155. Daemons' output file descriptors are handled somewhat awkwardly
  156. by various daemontools implementations. For example, for runit tools,
  157. daemons' stdout goes to wherever runsvdir's stdout was directed;
  158. stderr goes to runsvdir, which in turn "rotates" it on its command line
  159. (which is visible in ps output).
  160. Hopefully this get changed/standardized; while it is not, the "run" file
  161. should start with a
  162. exec 2>&1
  163. command, making stderr equivalent to stdout.
  164. An especially primitive service which does not want its output to be logged
  165. with standard tools can do
  166. exec >LOGFILE 2>&1
  167. or even
  168. exec >/dev/null 2>&1
  169. To prevent creation of distro-specific log/ directory, a service directory
  170. in /etc/rc can contain an empty "log" file.
  171. Controlling daemons
  172. The "svc" tool is available for admins and scripts to control services.
  173. In particular, often one service needs to control another:
  174. e.g. ifplugd can detect that the network cable was just plugged in,
  175. and it needs to (re)start DHCP service for this network device.
  176. The name of this tool is not standard either, which is an obvious problem.
  177. I propose to fix this by implementing a tool with fixed name and API by all
  178. daemontools clones. Lets use original daemontools name and API. Thus:
  179. The following form must work:
  180. svc -udopchaitkx DIR
  181. Options map to up/down/once/STOP/CONT/HUP/ALRM/INT/TERM/KILL/exit
  182. commands to the daemon being controlled.
  183. The form with one option letter must work. If multiple-option form
  184. is supported, there is no guarantee in which order they take effect:
  185. svc -it DIR can deliver TERM and INT in any order.
  186. If more than one DIR can be specified (which is not a requirement),
  187. there is no guarantee in which order commands are sent to them.
  188. If DIR has no slash and is not "." or "..", it is assumed to be
  189. relative to the system-wide service directory.
  190. [Currently, "svc" exists only in daemontools and in busybox.
  191. This proposal asks developers of other daemontools implementations
  192. to add "svc" command to their projects]
  193. The "svok DIR" tool exits 0 if service is running, and nonzero if not.
  194. Other tools with different names and APIs may exist; however
  195. for portability scripts should use the above tools.
  196. Creation of a new service on a running system should be done atomically.
  197. To this end, first create and populate a new /etc/rc/DIR.
  198. Then "activate" it by running ??????? - this copies (or symlinks,
  199. depending on the distro) its files to the "live" service directory,
  200. wherever it is located on this distro.
  201. Removal of the service should be done as follows:
  202. svc -d DIR [DIR/log], then remove the service directory:
  203. this makes service monitor SIGTERM per-directory supervisors
  204. (if they exist in the implementation).
  205. Implementation details
  206. Top-level service monitor program name is not standardized
  207. [svscan, runsvdir, s6-svscan ...] - it does not need to be,
  208. as far as daemon packagers are concerned.
  209. It may run one per-directory supervisor, or two supervisors
  210. (one for DIR/ and one for DIR/log/); for memory-constrained systems
  211. an implementation is possible which itself controls all services, without
  212. intermediate supervisors.
  213. [runsvdir runs one "runsv DIR" per DIR, runsv handles DIR/log/ if that exists]
  214. [svscan runs a pair of "supervise DIR" and "supervise DIR/log"]
  215. Directories are remembered by device+inode numbers, not names. Renaming a directory
  216. does not affect the running service (unless it is renamed to a .dotdir).
  217. Removal (or .dotdiring) of a directory sends SIGTERM to any running services.
  218. Standard output of non-logged services goes to standard output of service monitor.
  219. Standard output of logger services goes to standard output of service monitor.
  220. Standard error of them always goes to standard error of service monitor.
  221. If you want to log standard error of your logged service along with its stdout, use
  222. "exec 2>&1" in the beginning of your "run" script.
  223. Whether stdout/stderr of service monitor is discarded (>/dev/null)
  224. or logged in some way is system-dependent.
  225. Containers
  226. [What do containers need?]