Introduction
The default init scheme in Dragora is known as Runit.
Runit is a cross-platform Unix init scheme with service supervision.
Runit is a replacement for the traditional sysvinit, and other init schemes. Was implemented
in Dragora 2.0 and pretends to be the default startup system for future releases.
Features
- Service supervision
-
Each service is associated with a service directory, and each service daemon runs as a child
process of a supervising runsv process running in this directory. The runsv program
provides a reliable interface for signalling the service daemon and controlling the service
and supervisor. Normally the sv program is used to send commands through this interface,
and to query status informations about the service.
The runsv program supervises the corresponding service daemon. By default a service is
defined to be up, that means, if the service daemon dies, it will be restarted. Of course,
you can tell runsv otherwise.
This reliable interface to control daemons and supervisors obsoletes pid-guessing programs,
such as pidof, killall, which, due to guessing, are prone to failures by design.
It also obsoletes so called pid-files, no need for each and every service daemon to include
code to daemonize, to write the new process id into a file, and to take care that the file
is removed properly on shutdown, which might be very difficult in case of a crash.
- Clean process state
-
Runit guarantees each service a clean process state, no matter if the service is activated
for the first time or automatically at boot time, reactivated, or simply restarted. This means
that the service always is started with the same environment, resource limits, open file
descriptors, and controlling terminals.
You don't necessarily have that with sysv init scripts for example. It requires a carefully
written init script that reliably cleans up and sets the process state before starting the
service daemon. This adds even more complexity to the init script in comparison with a run
script used by runit. Many of today's init scripts don't provide a clean process state, here is
an example on what could happen:
# /etc/rc.d/foo-daemon start
Starting foo daemon: food.
#
Fine. Everything works, nothing to worry about. After rebooting the system this shows up on
the screen:
...
Starting foo daemon: food: command not found
failed.
...
The food program is installed in /opt/foo/bin/. When starting the service for the first
time using the init script, the PATH environment variable contained /opt/foo/bin.
After reboot init started the service using the init script, but with a different value for
the PATH variable, not containing /opt/foo/bin. Of course the init script should have
set PATH before starting the daemon; the problem is that it worked in the first place,
and that the error didn't show up until system reboot.
With bad init scripts miraculous things could also happen when just doing
# /etc/rc.d/foo-daemon restart
at the command line.
The clean process state includes open file descriptors, obsoleting the widely used hack in
many service daemons to force-close all file descriptors that might be open, up to the
limit of available file descriptors for the daemon process (often results in 1024
unnecessary close() system calls in a great number of service daemon implementations).
- Reliable logging facility
-
The runsv program provides a reliable logging facility for the service daemon.
If configured, runsv creates a pipe, starts and supervises an additional log service,
redirects the log daemon's standard input to read from the pipe, and redirects the service
daemon's standard output to write to the pipe. Restarting the service does not require
restarting the log service, and vice versa.
The service daemon and the log daemon can run with different process states, and under
different user id's. runit supports easy and reliable logging for service daemons running
chroot'ed.
If runsv is told to shutdown a service, e.g. at system shutdown, it ensures that the
log service stays up as long as the corresponding service daemon is running and possibly
writing to the log.
- Fast system boot up and shutdown
-
After the system's one time tasks (Stage 1) are done, the system services are started up
in parallel. The operating system's process scheduler takes care of having the services
available as soon as possible.
On system shutdown, Stage 3 uses runsv's control interface to wait until each service
daemon is terminated and all logs are written. Again, services are taken down in parallel.
As soon as all services are down, system halt or system reboot is initiated.
- Small code size
-
One of the runit project's principles is to keep the code size small. As of version 1.0.0 of
runit, the runit.c source contains 330 lines of code; the runsvdir.c source is 274 lines of
code, the runsv.c source 509. This minimizes the possibility of bugs introduced by programmer's
fault, and makes it more easy for security related people to proofread the source code.
The runit core programs have a very small memory footprint and do not allocate memory dynamically.
How works?
The program runit is intended to run as Unix process no 1, it is automatically started by
runit-init(8) through /sbin/init.
Stages
runit performs the system's booting, running and shutting down in three stages:
- Stage 1. runit starts /etc/runit/1 and waits for it to terminate. The system's one
time initialization tasks are done here. /etc/runit/1 has full control over
/dev/console to be able to start an emergency shell in case the one time initialization
tasks fail.
- Stage 2. runit starts /etc/runit/2 which should not return until the system is
going to halt or reboot; if it crashes, it will be restarted. Normally, /etc/runit/2
runs runsvdir. In Stage 2, runit optionally handles the INT signal (CTRL-ALT-DEL
keyboard request).
- Stage 3. If runit is told to halt or reboot the system, or Stage 2 returns without errors,
it terminates Stage 2 if it is running, and runs /etc/runit/3. The systems tasks to
shutdown and halt or reboot are done here.
Scheme
A description of the scheme configured on Dragora about the directories and files of Runit.
- /service
-
Service directory. Normally, is a symbolic link to the current runlevel in which you are
actually running.
- /etc/sv
-
Service directory with service daemons for runit.
- /etc/runit
-
Contains the three stages for runit (files: 1 2 3) and the ctrlaltdel file to handle
the keyboard request. Also contains the runsvdir directory. (See below).
- /etc/runit/runsvdir
-
This directory includes a sub-directory associated to a runlevel. For example:
/etc/runit/runsvdir/single provides some services from /etc/sv for the
single-user mode. Two symbolic links (current and previous) are provided to know
in which runlevel you are, and which one was the previous level.
- /etc/rc.d
-
The /etc/rc.d directory was designated for background services and the use of
other commands. Since runit, want the daemons to run in foreground.
Programs
|
Description: |
| runit |
Performs the system's booting, running, and shutdown in three stages. |
| runit-init |
The first process the Kernel starts. If runit-init is started as process no 1, it runs and replaces itself with runit(8). |
| runsv |
Starts and monitors a service and optionally an appendant log service. |
| runsvdir |
Starts and monitors a collection of runsv(8) processes. |
| runsvchdir |
Change services directory of runsvdir(8). |
| sv |
Control and manage services monitored by runsv(8). |
| chpst |
Runs a program with a changed process state. |
| utmpset |
Logout a line from utmp and wtmp file. |
Services
Managing services
Examples to manage services with sv(8).
- Query the status of a service
-
# sv status dhclient or # sv check dhclient
- You can check the status of a service to see if it's running or not.
- Query the status of all services
-
# sv status /service/* or # sv check /service/*
- Note: If service doesn't start with a dot or slash and doesn't end with a slash,
it is searched in the default services directory /service/, otherwise relative
to the current directory.
- Stopping a service
-
# sv stop sshd
- Starting a service
-
# sv start sshd
- Restarting a service
-
# sv restart sshd
- Send signals to a service
-
# sv hup wicd
Removing services
To detach a service, just remove the symbolic link under /service/ pointing to the
service directory (/etc/sv/); runit recognizes the removed service within the next
five seconds, then stops the service, the optional log service, and finally the supervisor
process. e.g.:
# rm -v /service/xinetd
- Attaching the removed service (again)
-
# ln -s /etc/sv/xinetd /service
Creating services
Let's see some examples that are provided in the distribution:
$ cat /etc/sv/cupsd/run
#!/bin/sh
#
# cupsd: Common unix printing system daemon.
#
if [ -x /usr/sbin/cupsd ]; then
exec /usr/sbin/cupsd -f
fi
As you can see, the first line is the shell (/bin/sh) followed by a comment. On the
left side of the commentary, is the name of the service, and on the right side:
a brief description. Then, a condition checks that the service is an executable.
The option -f is passed to cupsd to run cupsd in foreground.
What about a service depend on another service?
Make sure in the ./run script of the dependant service that the service it depends on
is available before the service daemon starts. The sv program can be used for that.
e.g. the klogd service wants the syslogd system logging service to be available before
starting the klog service daemon. (Check the line 7).
$ cat -n /etc/sv/klogd/run
1 #!/bin/sh
2 #
3 # klogd: Kernel log daemon.
4 #
5
6 if [ -x /sbin/klogd ]; then
7 sv up syslogd || exit 1;
8 exec /sbin/klogd -n -c 4 -x
9 fi
10
Runlevels
Two runlevels are provided by default, they are called: default and single. The "default"
runlevel contains all the daemons included on /etc/sv. The "single" runlevel, includes
one service of tty for the single-user mode. So, you can create more runlevels attaching
services - according to your needs. For example:
# mkdir /etc/runit/runsvdir/myrunlevel
# ln -sv /etc/sv/getty-tty1 /etc/runit/runsvdir/myrunlevel
# ln -sv /etc/sv/getty-tty2 /etc/runit/runsvdir/myrunlevel
# ln -sv /etc/sv/sshd /etc/runit/runsvdir/myrunlevel
# ln -sv /etc/sv/gpm /etc/runit/runsvdir/myrunlevel
# ln -sv /etc/sv/klogd /etc/runit/runsvdir/myrunlevel
# ln -sv /etc/sv/syslogd /etc/runit/runsvdir/myrunlevel
Switching runlevels with runit is done by switching the directory the runsvdir program
is running in. This is done by the runsvchdir program, e.g. to switch to the single user
runlevel, do:
# runsvchdir myrunlevel
To switch back to the default runlevel, do:
# runsvchdir default
References
To learn more about runit, see the manual pages. Also check this links:
08 August 2012, 17:10 |
(GNU Free Documentation License |
Validate HTML)