[Nix-dev] How to get rid of systemd (was: Modifying the init system (introducing S6 supervision suite))

Ertugrul Söylemez ertesx at gmx.de
Sat Dec 27 07:48:45 CET 2014


Hi there Anderson,

> I want to know if it's possible to use an alternate to Systemd as init
> system on NixOS.

this has been asked many times now, and I'm in favour of switching to an
alternative.  Unfortunately it's not easy, because a considerable
portion of NixOS currently depends on systemd, most notably the services
infrastructure and pretty much all container-related stuff.  Note that
systemd is not just an init system.

One thing most of us seem to agree about is that conceptually NixOS does
not depend as much on something like systemd as most other distributions
do.  In principle most of what systemd does could be handled by the
activation script and perhaps a custom daemon (or even just a set of
scripts) that allows us to manage the services that are part of the
current system derivation.  NixOS can deal with things like cgroups or
ACPI events in a more sensible, repeatable and transparent way.

I would go as far as to say that systemd is the number one thing that
cripples us in many ways.  Switching to it was a huge step back from the
ideals of NixOS, because it represents all the traditional views on what
a system should look like: a giant pile of interconnected mutable
variables.  Remember that immutability is not only about the filesystem.


How to get rid of systemd
=========================

I think as a first step to get rid of systemd and gain a much more
sensible services model as well we should move away from NixOS modules
for services.  At this point we are trapped in the traditional view that
services preexist and we get to enable/disable them.  Our system is
defined by a large set of switches and global settings.  This needlessly
robs us of a lot of flexibility, for example to run multiple instances
of the same daemon or to give us a choice to use our already running
preferred webserver when installing a web application as a service.

It also corrupts our ability to reason about the resulting system,
because enabling a certain service might trigger settings in some other
part of the system configuration to change.  This has actually bitten me
in the past.  Being able to reason about the resulting system is very
important.

I would prefer and do propose an algebraic solution (view services as a
toolbox from which you can pick the services you want and compose them
together).  A services configuration then might look like this:

    services =
        bitlbee { port = 10000; stateDir = "/var/lib/bitlbee1"; } <>
        bitlbee { port = 10001; stateDir = "/var/lib/bitlbee2"; } <>
        nginx { httpConfig = "..."; } <>
        postfix { postMasterAlias = "blah"; }

The big difference is that now services are first class values and form
a monoid under composition, which brings a number of advantages:

  * It allows us to run multiple instances of a daemon with slightly
    different configurations, as those are really just similar but
    otherwise unrelated services.

  * Services can take services as arguments, which would become the
    primary way to construct a dependency graph.  Think of a web
    application depending on a webserver or the other way around.

  * We could develop a fully automated way for services in different
    containers to communicate with each other.

  * Now people like me can actually use equational reasoning to
    understand and make predictions about the resulting system.  I can
    use the fact that the `<>` operator is associative, that certain
    services are idempotent with respect to `<>` and also that certain
    functions are morphisms in a rich category.  For example if the
    nginx function is a monoid morphism, then I know that regardless of
    how I compose multiple webservers, the result will be a sensible
    combination of either separate daemons or multiple configurations.
    This would be extremely valuable.

The last point is very important, because it basically tells that a
service is not directly related to what programs will run on the
resulting system.  Even if you compose ten nginx services, there will be
only one nginx *program* with a suitable configuration file to represent
this composition.  It also means that when a service itself comes with
nginx, then adding another nginx does not actually mean that two
instances will be running.  If we go as far as to containerise services
by default, we can make predictions about the container's structure.

As a final bonus this is so difficult and ugly to solve with systemd
that we would feel a much greater temptation to get rid of it. =)

Let me know what you think.  If this idea finds acceptance, I'm happy to
develop a formal model and a prototype.


Greets,
Ertugrul


More information about the nix-dev mailing list