(January 2017)
runit is a multi-platform init system. runit’s process sueprvisor can be used on top of a non-runit init.
Things that attracted me to runit:
runit-init
replaces /sbin/init
.
The command init 0
tells runit to halt the system.
init 6 reboots it.
The
runsvdirand
runsvchdir` programs handle runlevels.
Service dependencies are resolved automatically.
runit reads service configurations from subdirectories of /service/
.
runit also keeps state information (e.g. the service PID) in the /service/
subdirectories.
(Note: on some systems, /service
might be /etc/service
or even /var/service
.)
Several binaries make up runit:
sv
controls and manages services monitored by runsv
.runsv
starts and monitors a service and optionally an appendant log service.runsvdir
starts and monitors a collection of runsv
processes.runsvchdir
changes the services directory of runsvdir
(i.e. switches the “runlevel”).svlogd
is runit’s service logging daemon.chpst
runs a program with a changed process state (e.g. set the user id of a program, or renice a program)utmpset
modifies the user accounting database utmp to indicate that the user on the terminal line logged out.When acting as the system init, runit has three stages:
/etc/runit/1
and waits for it to terminate. This handle one-time system initialization tasks./etc/runit/2
. This keeps running (if all goes well) until system reboot or halt. If stage two crashes, it restarts./etc/runit/3
runs tasks to cleanly bring down the machine.Each of these three stages may be very simple shell scripts.
Here the sample of 1
from Debian Sarge:
#!/bin/sh
# system one time tasks
PATH=/command:/sbin:/bin:/usr/sbin:/usr/bin
/etc/init.d/rcS
/etc/init.d/rmnologin
touch /etc/runit/stopit
chmod 0 /etc/runit/stopit
Here the sample of 2
from Debian Sarge:
#!/bin/sh
PATH=/command:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin
exec env - PATH=$PATH \
runsvdir -P /etc/service 'log: ...........................................................................................................................................................................................................................................................................................................................................................................................................'
Here the sample of 2
from Debian Sarge:
#!/bin/sh
exec 2>&1
PATH=/command:/sbin:/bin:/usr/sbin:/usr/bin
LAST=0
test -x /etc/runit/reboot && LAST=6
echo 'Waiting for services to stop...'
sv -w196 force-stop /etc/service/*
sv exit /etc/service/*
echo 'Shutdown...'
/etc/init.d/rc $LAST
runit can act as a pure process supervisor, started by another init system.
The init system simply runs stage two of runit, typically by running runsvdir
as a service.
On SysV Init, for example, add an entry for /sbin/runsvdir-start
to /etc/inittab
.
runit will need the 2
script copied to /sbin/runsvdir-start
and the /service
directory created:
# install -m0750 /package/admin/runit/etc/2 /sbin/runsvdir-start
# mkdir -p /service
First, create a new service directory.
Second, create a run
script in the new service directory, and make it executable.
# mkdir -p /etc/sv/myservice/
# touch /etc/sv/myservice/run
# chmod a+x /etc/sv/myservice/run
For use with runit, service daemon should not background themselves.
In the run
script, use exec
to have the script replace itself with the newly run daemon.
Here’s an example run
script to start getty
:
#!/bin/sh
exec getty 38400 tty2 linux
To tell runit about the new service, and run it on boot, create a link in the /service/
directory.
runnit should notice the next time it checks /service/
(about every five seconds).
# ln -s /etc/sv/myservice /service/
That’s pretty much it.
runnit can handle dependencies.
Just have the service’s run
file check if the dependency is running yet using sv
:
#!/bin/sh
sv start my-earlier-service || exit 1
exec my-later-service
To add an appendant log, create a /log/
subdirectory with another run
script.
# mkdir -p /etc/sv/myservice/log
# touch /etc/sv/myservice/log/run
# chmod a+x /etc/sv/myservice/log/run
The run
script should run a logging daemon, like:
#!/bin/sh
exec chpst -ulog svlogd -tt ./main
# sv hup myservice
# sv status myservice
# sv up myservice
# sv down myservice
[The notes below are slightly older, and contain some repetition of the above.]
Each service has a service directory.
Each service runs as a child of a supervising runsv
process that operates out of the service directory.
This obviates the need to guess about service PID’s or to write pidfiles.
# sv up /service/myservice
# sv status /service/myservice
# sv down /service/myservice
# sv restart /service/myservice
# sv hup /service/myservice
The /service/
directory holds symlinked directories for each of the processes currently enabled.
The symlinks point to /etc/sv/
, which contains directories with configs for enabled and disabled services.
(This is a bit like Apache2’s /etc/sites-enabled/
and /etc/sites-available/
.)
Each service directory contains a run
file — a simple shell script to start the process, like:
#!/bin/sh
exec /usr/local/sbin/exim -bdf -q30m
See example run
scripts at http://smarden.org/runit/runscripts.html.
The run
scripts handle this.
If a run
script returns non-zero, runit will try it again later.
So, here’s a run
script for “bar” that makes sure “foo” has already started:
#!/bin/sh
sv start foo || exit 1
exec bar --myoption
http://smarden.org/runit/runlevels.html
Runlevels correspond to directories in /etc/runit/runsvdir/
.
Switching runlevels is done by switching the directory the runsvdir program is running in with runsvchdir
:
# runsvchdir single
# runsvchdir default
Create a custom runlevel by making a new directory in /etc/runit/runsvdir/`, and symlinking the directories of the services we want into that directory.
New versions of busybox include runit. This makes busybox attractive as an LXC container template.
Unfortunately, the version of busybox shipped with Debian Stretch is too old to include runit. Here’s how to use a newer busybox to make a runit lxc container on Debian.
sudo lxc-create -n mybusybox -t busybox
.sudo cp ~/Download/busybox-x86_64 /var/lib/lxc/mybusybox/rootfs/bin/busybox
.# mkdir -p /etc/sv /etc/service /etc/runit/runsvdir
# ln -s /etc/service /service
/bin/
for chpst
, runsv
, runsvdir
, sv
, and svlogd
, like:# busybox --list | awk '/runsv|chpst|svlog|^sv$/' | xargs -I{} ln -sv /bin/busybox /bin/{}
/sbin/runsvdir-start
:#!/bin/sh
PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin
exec env - PATH=$PATH \
/bin/runsvdir /service 'log: ....................................................................................'
/etc/initab
:# cat >>/etc/inittab <<EOF
::respawn:/sbin/runsvdir-start
EOF
NO, THE BELOW ISN’t QUITE RIGHT YET.
The version of Busybox in Alpine (3.6) does not include the runit applets, so we must download the official Busybox build.
# lxc-create -n test-alpine -t alpine -- -r v3.6
$ cd /tmp
$ wget https://www.busybox.net/downloads/binaries/1.26.2-i686/busybox
# cp /tmp/busybox /var/lib/lxc/alpine-runit/rootfs/bin/
# lxc-start -n alpine-runit
# lxc-attach -n alpine-runit
# busybox --list | awk '/runsv|chpst|svlog|^sv$/' | xargs -I{} ln -sv /bin/busybox /bin/{}
# ln -s /bin/busybox /usr/bin/runsvdir
# rc-update add runsvdir boot
The /etc/init.d/runsvdir
(which mysteriously comes with Alpine although runit does not), expects our runit service directory to be /run/openrc/sv
… no, that’s a tmpfs….?
https://kchard.github.io/runit-quickstart/
# apt-get install runit
# ps -ef | grep runsvdir
The ps
output should include something like runsvdir -P /etc/service …
.
This shows the directory runsvdir
watches for service files.
To add a new service, create a new subdirectory in /etc/service
.
Create a run
script in the new service subdirectory, like:
#!/bin/sh -e
exec 2>&1
exec chpst -u foo /usr/local/bin/foo
Create a log directory (/var/log/foo
).
Create a log
script, like:
#!/bin/sh
exec chpst -u foo svlogd -tt /var/log/foo
# sv status foo