Saturday, January 9, 2016

A comparison of alternatives to init(8) and rc(8)

(Full disclosure: I am the author of relaunchd, one of the projects being evaluated in this article)

There are several projects underway to create a new system initialization and service management framework for FreeBSD and other Unix-like systems. This article compares three of these projects:

The boot process

For the purpose of this discussion, the boot process can be broken into three stages:
  1. the boot loader, loader(8)
  2. the primordial process, init(8)
  3. the run control service, rc(8)
The functions of the boot loader will not be covered in this article.

The boot loader hands control to init, which has the following basic responsibilites:
  • enter single user mode, if requested
  • spawn a number of getty(8) terminals for the console
  • launch the rc mechanism
After performing its duties for the early part of the boot process, the init process continues running in the background to perform several other duties:
  • restarting getty if it dies
  • reaping orphaned child processes
  • waiting for a signal to reboot or shutdown the system
The rc mechanism is a set of shell scripts that determine what services to start, and in what order. Once everything has been started, the rc process terminates.

Problems with the current process

While the current init and rc mechanism are classic parts of the Unix design, there are several reasons why people are interested in replacing them:
  • reliability - if a service dies, the rc mechanism will not automatically restart it;
  • performance - services are started in a serial fashion, which is slow and does not take advantage of the parallelism of today's multi-core hardware;
  • security - the shell scripts that rc uses do not allow for the enhanced security features that are possible in other systems.
  • complexity - shell scripts are programs, which makes them more difficult to manage than simple configuration files used by most modern alternatives.
  • dependency management - the rc system requires service dependencies to be explicitly defined in each rc script. In many alternative systems, dependencies are automatically handled through mechanisms like socket activation.
  • features - the rc system has a stable interface which limits the ability to extend it with new features. It is only able to handle basic functions like starting, stopping, and checking if the service has died.

Proposed solutions

This article takes a look at three of the proposed solutions.

launchd

The NextBSD project has ported the original launchd from Apple, and offers a very close approximation to the experience of using launchd in OS X. One major difference is that within NextBSD, the launchd.plist(5) jobs are specified using JSON instead of XML.

To achieve this feat, the NextBSD developers wrote a Mach compatibility layer that allows launchd to use Mach IPC and (possibly) other features of Mach.

relaunchd

The relaunchd project has started from scratch and built a workalike to launchd without using any of the original code. It is not yet feature-complete, but a lot of progress has been made. It works under FreeBSD and Linux, and uses LibUCL to parse its configuration files.

Unlike the two other projects in this article, relaunchd is explicitly designed not to replace init(8) and rc(8). Instead, it is intended to provide additional features and benefits to users programs that want them, and to not disrupt the existing initialization and boot system. The idea is that programs will gradually see the benefits of switching to relaunchd management, and the number of things being managed under the traditional rc mechanism will gradually shrink to almost nothing.

nosh

The nosh project does not aim to be a clone of launchd; rather, it tries to take the best features of all of the modern rc/init replacements and combine them into a new system. It has compatibility shims for systemd, Solaris' SMF, Red Hat's chkconfig/service, and OpenBSD's rcctl.

nosh has also been designed to work with FreeBSD and Linux.

Feature comparison


The table below gives a quick comparison between the three projects:

  launchd relaunchd nosh
Replaces init(8) and runs as PID #1 Yes No Yes1
Replaces rc(8) and manages all services Yes No Yes1
IPC mechanism Mach ports None currently; planned support for DBus and libipc None
Configuration file format JSON JSON2 Custom scripting language
Compatibility shims for systemd and other init systems No No Yes
Process supervision YesPlanned, but not implemented Yes
Cron replacement YesPlanned, but not implemented No
Milestones and targets No No Yes
Built-in syslog replacement No No Yes
1. Nosh allows you to experiment with running alongside an existing init/rc mechanism, but the documentation implies this is not the goal of the project.
2. Technically, jobs could be defined in any format that LibUCL supports, which (currently) is JSON, YAML, and nginx-style.