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