wiki:runit/replaceinit

Replacing init with runit on Debian GNU/Linux

This is based mostly on the notes on replacing init with runit written by Gerrit Pape, the main runit developer.

Install the needed Debian runit packages:

# aptitude install runit runit-services runit-run

init

The runit-run package installs the init replacement program, runit-int:

proton:~ 0# ls -al /sbin/init*
lrwxrwxrwx 1 root root    10 2007-12-21 18:40 /sbin/init -> runit-init
-rwxr-xr-x 1 root root 32652 2007-01-30 17:27 /sbin/init.sysv
proton:~ 0# 

runit-init's operation is very simple:

  • if it is started by root as process number one, then it just replaces itself with the runit program.
  • if not called by the kernel, then it is called as "init 0" to halt the system, or "init 6" to restart the system.

runit

The runit program executes three stages in succession:

  1. /etc/runit/1 - executes one-time system tasks, roughly equivalent to /etc/rcS.d (in fact it actually calls /etc/init.d/rcS, which in fact does this)
  2. /etc/runit/2 - changes the runlevel to "default" and starts runsvdir on /var/service (which is linked to the current runlevel directory). returns when the system is to be shutdown
  3. /etc/runit/3 - shuts down the system

runit runlevels

runit has runlevels that are defined in /etc/runit/runsvdir:

proton:~ 0# ls -al /etc/runit/runsvdir/
total 4
drwxr-xr-x 4 root root 1024 2007-12-21 18:40 .
drwxr-xr-x 3 root root 1024 2007-12-21 18:41 ..
lrwxrwxrwx 1 root root    7 2007-12-21 18:40 current -> default
drwxr-xr-x 2 root root 1024 2007-12-21 18:41 default
drwxr-xr-x 2 root root 1024 2007-12-21 18:40 single
proton:~ 0#

Each of these directories contain the services that are to be managed at the various runlevels. /var/service is a link to /etc/runit/runsvdir/current:

proton:~ 0# ls -al /var/service
lrwxrwxrwx 1 root root 27 2007-12-21 18:41 /var/service -> /etc/runit/runsvdir/current
proton:~ 0#

services

These are the default services setup for runlevel "default" by default:

proton:~ 0# ls -al /etc/runit/runsvdir/default/
total 2
drwxr-xr-x 2 root root 1024 2007-12-21 18:41 .
drwxr-xr-x 4 root root 1024 2007-12-21 18:40 ..
lrwxrwxrwx 1 root root   15 2007-12-21 18:40 getty-1 -> /etc/sv/getty-1
lrwxrwxrwx 1 root root   15 2007-12-21 18:40 getty-2 -> /etc/sv/getty-2
lrwxrwxrwx 1 root root   15 2007-12-21 18:40 getty-3 -> /etc/sv/getty-3
lrwxrwxrwx 1 root root   15 2007-12-21 18:40 getty-4 -> /etc/sv/getty-4
lrwxrwxrwx 1 root root   15 2007-12-21 18:40 getty-5 -> /etc/sv/getty-5
lrwxrwxrwx 1 root root   20 2007-12-21 18:41 socklog-klog -> /etc/sv/socklog-klog
lrwxrwxrwx 1 root root   20 2007-12-21 18:41 socklog-unix -> /etc/sv/socklog-unix
proton:~ 0# 

These service directories start the gettys, and the main system log daemons. Once you figure out what services you want managed in a particular runlevel, you have to make their service directories. The runit-services package comes with service directories for a bunch of standard services, all located in /etc/sv:

proton:~ 0# ls /etc/sv/
apache    dhcp     getty-2  nfs-kernel-server  socklog-inet       socklog-unix
chrony    exim     getty-3  portmap            socklog-klog       squid
cron      gdm      getty-4  postfix            socklog-notify     ssh
dhclient  getty-1  getty-5  README             socklog-ucspi-tcp  xdm
proton:~ 0# 

/etc/sv/README gives a good intro on how to get these services started on a sysv-init managed system. I'm going to start by getting the cron service working:

proton:~ 0# /etc/init.d/cron stop
Stopping periodic command scheduler: crond.
proton:~ 0# dpkg-divert --add /etc/init.d/cron
Adding `local diversion of /etc/init.d/cron to /etc/init.d/cron.distrib'
proton:~ 0# mv /etc/init.d/cron /etc/init.d/cron.distrib
proton:~ 0# ln -s /usr/bin/sv /etc/init.d/cron
proton:~ 0# ln -s /etc/sv/cron /etc/runit/runsvdir/default/
proton:~ 0# sv status cron
run: cron: (pid 2033) 2s
proton:~ 0#

That was simple. Now ssh:

proton:~ 0# /etc/init.d/ssh stop
Stopping OpenBSD Secure Shell server: sshd.
proton:~ 0# dpkg-divert --add /etc/init.d/ssh
Adding `local diversion of /etc/init.d/ssh to /etc/init.d/ssh.distrib'
proton:~ 0# mv /etc/init.d/ssh /etc/init.d/ssh.distrib
proton:~ 0# ln -s /usr/bin/sv /etc/init.d/ssh
proton:~ 0# ln -s /etc/sv/ssh/
log/       run        supervise  
proton:~ 0# ln -s /etc/sv/ssh /etc/runit/runsvdir/default/
proton:~ 0# sv status ssh
run: ssh: (pid 2059) 2s; run: log: (pid 2057) 2s
proton:~ 0# 

An important one to me, which is not included with runit-services, is a serial console. This is the simple service directory I wrote to put a getty on ttyS0:

proton:~ 0# ls -al /etc/sv/getty-S0/
total 4
drwxr-xr-x  2 root root 1024 2007-12-21 19:32 .
drwxr-xr-x 26 root root 1024 2007-12-21 19:26 ..
-rwxr-xr-x  1 root root   32 2007-12-21 19:27 finish
-rwxr-xr-x  1 root root   43 2007-12-21 19:30 run
lrwxrwxrwx  1 root root   20 2007-12-21 19:32 supervise -> /var/run/sv.getty-S0
proton:~ 0# cat /etc/sv/getty-S0/run 
#!/bin/sh
exec getty -L ttyS0 115200 vt102
proton:~ 0# cat /etc/sv/getty-S0/finish
#!/bin/sh
exec utmpset -w ttyS0
proton:~ 0# 

Once the service directory was ready, I commented out the serial getty line ("TO:...") in /etc/inittab, told the current running init to reload the inittab (ie. stop the getty on ttyS0), and then linked in the new service:

proton:~ 0# /sbin/init.sysv q
proton:~ 0# ln -s /etc/sv/getty-S0 /etc/runit/runsvdir/default/
proton:~ 0# ln -s /etc/sv/getty-S0 /etc/runit/runsvdir/single/
proton:~ 0# 

Notice I want it started in both "single" and "default" runlevels. The serial console started up no problem.

You can have runit supervise dhclient as well. In order to do this, you need to make sure ifupdown doesn't try to control it. If you want to have eth0 use dhcp, in /etc/network/interfaces take out any "auto eth0" lines, and change the "iface" line to read:

iface eth0 inet manual

This is just a place holder. Now all you need to do is kill any dhclient process running and link in the dhclient service dir:

proton:~ 0# ln -s /etc/sv/dhclient /etc/runit/runsvdir/default/
proton:~ 0# 

reboot!

Finally, reboot your system:

/sbin/init.sysv 6

Success!

proton:~ 0# pstree
runit─┬─events/0
      ├─khelper
      ├─ksoftirqd/0
      ├─kthread─┬─aio/0
      │         ├─kblockd/0
      │         ├─khubd
      │         ├─4*[kjournald]
      │         ├─kmirrord
      │         ├─kseriod
      │         ├─kswapd0
      │         └─2*[pdflush]
      ├─runsvdir─┬─2*[runsv─┬─socklog]
      │          │          └─svlogd]
      │          ├─runsv─┬─dhclient
      │          │       └─svlogd
      │          ├─runsv───svlogd
      │          ├─runsv─┬─sshd─┬─sshd───bash
      │          │       │      └─sshd───bash───pstree
      │          │       └─svlogd
      │          ├─runsv───getty
      │          └─runsv───cron
      └─udevd
proton:~ 0# 

todo

I'm curious about udevd. It's started in /etc/rcS.d, and therefore by /etc/runit/1, but it's not being managed by a runsvdir. I'm not sure what the best way to do that is.

Last modified 10 years ago Last modified on Dec 27, 2007, 6:00:58 PM