Running runit on Amazon Linux AMI

Unfortunately, runit supervisor is not so popular in RadHat-based distrubutions.

If you like runit simplicity and don’t want to give it up and use complex run scripts or write obscure upstart jobs, read ahead.

The trick is to use busybox: little all-in-one utility, used mostly as a rescue kit, during boot stage or in embedded environments.

Luckily, Amazon Linux AMI has busybox package in its base repositories, so you need to install it first:

# yum install busybox

Once installed, you can find it in /sbin/busybox. This little binary has great powers hidden inside: call busybox --list and you will get full list of supported commands. Each command can be called as busybox commandName, or via commandname symlink: you can create symlink called commandName to /sbin/busybox and call this symlink directly like a separate binary. We won’t need all of them to get runit up and running though, only these are sufficient:

# busybox --list | awk '/runsv|chpst|svlog|^sv$/'
chpst
runsv
runsvdir
sv
svlogd

Create symlinks:

# busybox --list | awk '/runsv|chpst|svlog|^sv$/' | \
    xargs -I{} ln -sv /sbin/busybox /sbin/{}

Now you have to run runsvdir. In debian-based distributions, runsvdir is traditionally started with SysV init /sbin/init process, as runsv package adds runsvdir to /etc/inittab. Amazon Linux AMI is a different story: it uses upstart as its init system, so we have to create upstart job to start runsvdir.

Let’s create service directories first:

mkdir -p /etc/sv /etc/service

The first one would contain actual service directories, enabled services would be symlinked to the second directory, which has to be tracked by runsvdir process.

Create upstart service for runsvdir:

<<EOF cat > /etc/init/runsvdir.conf
start on runlevel [2345]
stop on runlevel [S016]
respawn
exec /sbin/runsvdir -P /etc/service
EOF

Now check you have runsvdir up and running:

# status runsvdir
runsvdir start/running, process 1508

Running test service to check runit

Let’s create a basic service to check whether runit works ok.

Service directory:

mkdir -p /etc/sv/sleeper/log

Create service run script:

<<EOF cat > /etc/sv/sleeper/run 
#!/bin/sh -eu
exec 2>&1
env
exec sleep 360
EOF

Create log service run script:

<<EOF cat > /etc/sv/sleeper/log/run 
#!/bin/sh -eu
exec 2>&1
LOGDIR=/var/log/sleeper
test -d $LOGDIR || mkdir -p $LOGDIR
exec /sbin/svlogd -tt $LOGDIR
EOF

Make scripts executable:

find /etc/sv/sleeper -name run -exec chmod +x \{\} \+

Create symlink to service:

ln -sv ../sv/sleeper /etc/service

Now runsvdir should have automatically started your service, you can check it with sv command:

# sv s /etc/service/sleeper
run: /etc/service/sleeper: (pid 1619) 53s; run: log: (pid 1522) 1493s

Or look at process tree with ps fax:

 1508 ?        Ss     0:00 /sbin/runsvdir -P /etc/service
 1521 ?        Ss     0:00  \_ runsv sleeper
 1522 ?        S      0:00      \_ /sbin/svlogd -tt /var/log/sleeper
 1619 ?        S      0:00      \_ sleep 360

If you don’t like to put /etc/service before service name each time you call sv, you can use SVDIR environment variable:

# export SVDIR=/etc/service
# sv s sleeper
run: sleeper: (pid 1653) 283s; run: log: (pid 1522) 2443s