In this post, we'll look at how runlevels work in two major init systems, systemd and OpenRC. If you're interested in trying out systemd
, I'd suggest using an Arch Linux Live ISO. For those interested in trying OpenRC, check out Funtoo. Both of these will work great in your favorite virtualization solution.
OpenRC
OpenRC uses runlevels in very much the same way as sysvinit (or BSD init). At any given time the system is in one of the defined runlevels, there are three internal runlevels and four user defined runlevels.
Internal Runlevels:
sysinit
: Initialize the system.shutdown
: Power off the system.reboot
: Rebooting the system.
User Runlevels:
boot
: Starts all system-necessary services for other runlevels.default
: Used for day-to-day-operationsnonetwork
: Used when no network connectivity is required.single
: Single-user mode.
A system transitions between runlevels like so:
The services controlled by a particular runlevel are controlled by /etc/inittab
and via the rc-update
command.
On a modern Funtoo LXC Container, your runlevels might look like this:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Services can be added to runlevels with:
Or removed with:
Changing between runlevels is done via the rc <runlevel>
command, but most users will never need to do this as runlevels are (mostly) managed by the system.
In the case where a user does want to change runlevels in this way, it is often such that they are utilizing Stacked Runlevels.
For example, if a user wanted to differentiate which services were running on their laptop when it was powered or on battery, they could create two separate runlevels stacked atop default
. While plugged in, the laptop could be running test databases or any number of services, but after changing runlevels these services could be disabled to save on battery.
Benefits
- Simple: There are (normally) only 7 runlevels, and for most of it's time the system remains on the
default
runlevel. - Established:
init
andsysvinit
have been using runlevels for ages. - Sufficient: Runlevels have been shown to provide sufficient functionality for most applications.
Downfalls
- Inflexible: While there are ways to create 'Stacked Runlevels', the system is not very capable of more exotic requirements.
- Aging: Modern systems, especially desktops and laptops, frequently change their hardware (inserting a USB stick), or network settings (Changing between WiFi networks), steps have been taken by system designers to handle these stumbling blocks, but it's not longer always sufficient to scan once for hardware, for example.
systemd
systemd
uses targets instead of runlevels. Each target has a unique name, and multiple targets can be active at one time. Since most distributions using systemd have migrated from a runlevel based init system, there are targets which roughly correspond to the runlevels used by OpenRC, init
, and sysvinit
.
poweroff
: Halt the system.rescue
: Single user mode.multi-user
: Multi-user, non-graphical. User-defined/Site-specific runlevels.graphical
: Multi-user, graphical. Usually multi-user + graphical login.reboot
: Rebootemergency
: Emergency Shell
It's important to understand that these are not necessarily the only active targets. In the case of the graphical
target, a display manager service like kdm
might be started, this target would also activate the multi-user
target.
The multi-user
target might also activate a service like dbus
, and another target named basic
. This is interesting because it allows us to cleanly compose and extend the system to suit our needs.
A .target
file resides in /usr/lib/systemd/system
or /usr/lib/systemd/system/
and looks like this:
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
After=multi-user.target
Conflicts=rescue.target
Wants=display-manager.service
AllowIsolate=yes
This file would be accompanied by a <target>.wants
directory containing the services it should enable.
Targets can be controlled very similar to systemd's .service
unit files, you just need to add .target
at the end.
; )
;
)
The .target
based approach allows for various services to be grouped in a logical manner. For example, is is the state of targets on a modern Fedora Desktop:
)
)
)
Benefits
- Composition: Allows for services to be composed together in logical, user-defined groups easily.
- Configuration: It's simple to add custom targets.
- Less Restrictive: Since multiple targets can be active at a given time, the system's behavior can be more finely defined.
Downfalls
- Complexity: A sufficiently sophisticated installation could be composed of dozens of targets, and can require a deeper understanding of the system.