Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC 0163] Portable Service Layer #163

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

svanderburg
Copy link
Member

@svanderburg svanderburg commented Oct 5, 2023

This RFC proposes a generic, portable service layer that makes it possible to manage services on top of (in theory) any operating system that is capable of running the Nix package manager.

Rendered

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfc-0160-portable-service-layer/33886/1

Comment on lines 482 to 486
Compared to NixOS and other solutions, such as nix-darwin and system-manager,
another feature of the Nix process management framework is that services are
units of *instantiation* rather than *singleton* objects -- in NixOS, services
are bound to modules. As a result, services are singleton objects that only have
a single implementation and a single configuration.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I talked to you at Nixcon about exactly this, where I even created a gist for you to demonstrate how the module system can be used to support instances of services. The module system is slowly becoming the dominant way to write composable and modular Nix code, and I really think it should be used for this too. This will make integration into NixOS easier too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to add examples for the other two scenarios as well. Indeed, the gist that you gave me is a way to use the modular-style for multi-instance purposes.

I'd also like to explore the third option that I gave -- the hybrid approach between the functional style and the NixOS module system.

I'd like to show all three scenarios, because each of them have pros and cons. The benefit of the functional/pkgs style is that it is less memory consuming and components are configured on a need-to-know basis. The downside is obviously that you can only define one system aspect and not combine multiple aspects into one (e.g. such as adding programs to the PATH etc). Also, the NixOS module system has a "type system" which the functional style doesn't use.

The NixOS modular style is beneficial because it does fit well in the current conventions, it can be used to combine multiple system aspects into one and use of the type system to prevent certain kinds of errors. One of its major drawbacks is memory consumption/evaluation time.

The hybrid approach is something I still need to explore. Maybe it can be good a trade-off between the convenience of combining multiple aspects into one and the need-to-know properties of the functional style.

I'd like to see that we consciously pick the most suitable option out of these three.

Exploring this may take some time, maybe I'll ask you for some help @infinisil

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I talked to you at Nixcon about exactly this [...]

... too, but I did not write a gist. My suggestion was to use imports.

After all, anything you can do by calling an arbitrary function, you can do by importing into a submodule.

Using it might look something like

# NixOS configuration.nix
{ config, lib, serviceModules, ... }:
{
  services.app-db = {
    imports = [ serviceModules.postgresql ];
    listenPort = 15432;
  };
}

One of its major drawbacks is memory consumption/evaluation time.

That's mostly a scaling problem with the current (anti?)pattern of using a massive module list that's always loaded.
Using imports as above, that's solved.

A constant factor overhead does remain, but it's a very small price worth paying for a few service definitions, as opposed to, say, large package sets.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer something closer to @roberth's, because explicitly collecting all the instances in one place is also not terribly modular. (Feels to SQL like me, with out enough type vs table distinction.)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels to SQL like me, with out enough type vs table distinction.

Do you have a link to a page that expands on this issue? I at least am not familiar enough with SQL (or its intersection with type theory) to understand this remark.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@roberth maybe i'm a bit dense and this doesn't make automatic sense to me... but i was really hoping you could explain your ideas to me - sounds really interesting.

sorry for the hassle!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I even created a gist for you to demonstrate how the module system can be used to support instances of services.

The fact that there are no examples of this technique actually being used is probably meaningful here.

@svanderburg's point remains: with Nix functions and packages you don't have to do anything special in order to "multi-instance enable" them. It's automatic. The gist above requires extra work in order to make a service "multi-instance aware", and comes at a cost to people who only want one instance.

We should strive for a service abstraction that makes multiple instances effortless, the way /nix/store makes it effortless to have multiple versions of the same package installed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might end up using both something like the gist and my example because they solve different problems.

  • @infinisil's gist operates at the NixOS level, allowing a "constellation" of services to be configured in one go. For example you could have a module that sets up an entire web application with local reverse proxy, database, etc, which would be counterproductive to do in a single systemd service.
  • my example operates within a single service. This solves one of the gripes people have, that a NixOS module can affect any aspect of the system - no principle of least authority. In my example, the service module can only affect the system in ways that are explicitly facilitated by the system. For instance it can not add a file to /etc or create a user unless a proper NixOS module (ie the service abstraction layer implementation) inspects the service submodules and acts on them as it sees fit.

I imagine a crossover is also possible, where such "constellations" are defined in isolation just like individual services, but are only allotted a certain prefix of unit names for example.

Btw surely someone has come up with a better name than constellation for this.

I'll try to demonstrate the principle with a working example. (no constellations probably. that's mostly just the same pattern applied twice. interesting though. we'll see)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my example, the service module can only affect the system in ways that are explicitly facilitated by the system. For instance it can not add a file to /etc or create a user unless a proper NixOS module (ie the service abstraction layer implementation) inspects the service submodules and acts on them as it sees fit.

thanks for the explanation! looking forward to seeing your example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, did the thing. A bit rushed maybe, but a lot more complete than anything I wrote before this.

to be operating system agnostic.

# Prior art
[prior-art]: #prior-art
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised for you to not mention your own Disnix/Dysnomia projects. It's clear that that's where this RFC comes from.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking for something like this, I wast pointed to https://devenv.sh/services/ as the most likely current candidate. I think it would make sense to add that to prior art as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or kubenix, or arion (which piggybacks on NixOS instead of rewriting the service library again). Maybe more?
You might want to draw the line. They're just custom service managers for which this RFC proposes to create a common interface. If someone has a repo for services on S6, would that change the design? Probably not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've expanded this section a bit. The reason why I didn't add my own projects is because they are only loosely coupled to process management -- in its current state, whenever Disnix needs to manage processes it invokes the Nix process management framework for that purpose.

I have also added devenv.

Comment on lines 883 to 885
The integration with NixOS module system still needs to be worked out in detail.
Currently, I can think of two scenarios. For this a discussion in the Nix
community is required.
Copy link
Member

@infinisil infinisil Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in full support of this general idea. However this RFC feels just like a blog post as is, it needs to be much more concrete about how this idea should be practically implemented. It's also very long and could be trimmed down a lot by removing implementation details.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe that's true. On the other hand, the challenge is that the Nix process management is addressing multiple concerns at the same time that can be implemented in multiple ways. Choosing the implementation strategy is also something I'd like discuss. A notable example is the style in which process instances are specified.

For that reason, I think it's good to also provide a bit of context rather than only an implementation strategy, because this still needs to be decided.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it sounds like this RFC should be a draft instead

Comment on lines 883 to 885
The integration with NixOS module system still needs to be worked out in detail.
Currently, I can think of two scenarios. For this a discussion in the Nix
community is required.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This proposal might combine very well with the new pkgs/by-name directory introduced with RFC 140, because it could be extended to support a standard service.nix file to specify a standardised service definition for a package, without having to be tied to NixOS.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@infinisil can you please elaborate on your comment a bit? I'd like to make sure I understand you clearly. I'm not sure if you mean that this service.nix file would be an interface (options) without implementation (config), or something else... and to what extent the separation would go

I can imagine a service.nix which declares a common set of options for a module and then several other files (systemd.nix, supervisord.nix, launchd.nix, etc...) which define different implementations of these options (maybe even declaring some implementation specific options of their own). I love how this could tie into RFC 140!

Or did you have something else in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty much something like that yes. One of the potential future ideas with pkgs/by-name was to use it not only for package builds, but also the package-specific modules. So in addition to the current package.nix file in each directory, there could be a module.nix file or so too. This would then also be automatically discovered in some way and added to NixOS (or as here, more generic process management).

The reason I'm suggesting it here is because I imagine we need some kind of migration from the current NixOS modules to more generic modules, and combining that with a transition to pkgs/by-name could work nicely. I think of pkgs/by-name as a sort of strictly type-checked part of Nixpkgs, where CI prevents you from e.g. committing package.nix files that aren't packages. Similarly it could check that module.nix is a module with specific options or so.

Copy link
Member

@aanderse aanderse Oct 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love it! Thanks for confirming.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a standardised service definition

In other words, an API?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would then also be automatically discovered in some way and added to NixOS

We don't even have a module based implementation yet, so it's way too soon to start automating and imposing restrictions. This is a very different problem.
I'm all for grouping files by functionality instead of technical type, but easy on the rules please.

an API?

An interface.

"Application programming" just muddies the waters. It's 3 syllables either way.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This proposal might combine very well with the new pkgs/by-name directory introduced with RFC 140, because it could be extended to support a standard service.nix file to specify a standardised service definition for a package, without having to be tied to NixOS.

There is already at least one project doing exactly this.

@infinisil infinisil changed the title [RFC 160] Initial commit [RFC 163] Initial commit Oct 5, 2023
@infinisil
Copy link
Member

PSA: RFC numbers should match the PR number, so this is RFC 163. I updated the title, but make sure to also update the file path.

@svanderburg
Copy link
Member Author

PSA: RFC numbers should match the PR number, so this is RFC 163. I updated the title, but make sure to also update the file path.

Ah, I wasn't aware of this. I just updated the file

@2xsaiko
Copy link

2xsaiko commented Oct 5, 2023

The title of this PR should probably be "[RFC 163] Portable Service Layer" or something along those lines, not "Initial commit" :^)

launchd (on macOS) in combination with Nix to support process management.

To make service deployment accessible to a broader audience, it would be nice to
create a separation in the Nixpkgs tree for portable systemd services (e.g. a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: We already have support for building portable service images https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-portableService though I'd love it to be generalized to using the host's nix store instead of building a completely new image

* systemd is a Linux-specific tool. If we want to deploy a service on another
operating system, we need to pick a different solution that is compatible with
that operating system.
* systemd is glibc-specific. Sometimes, it may also be desired to manage
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we have a community-maintained set of patches that make systemd run on musl

@svanderburg svanderburg changed the title [RFC 163] Initial commit [RFC 163] Portable Service Layer Oct 6, 2023
@svanderburg
Copy link
Member Author

The title of this PR should probably be "[RFC 163] Portable Service Layer" or something along those lines, not "Initial commit" :^)

Indeed. I just updated the commit and PR title

@Atemu

This comment was marked as outdated.

Copy link
Member

@Atemu Atemu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am absolutely in favour of achieving this RFCs goal but there are two non-negotiable aspects about this topic that the RFC must address IMO:

It must stay compatible with NixOS module-style configuration.

If NixOS has some service defined, the user must be able to control its behaviour in every detail via their own module(s) using standard module functions such as mkMerge, mkForce and the like. In other words: It must stay composable.

It cannot come at the cost of unreasonable complexity or loss of functionality to NixOS maintainers.

If I, as a maintainer for some NixOS module, do not care for other init systems but systemd, I must be able to write the module in such a way that it is only compatible with systemd. Additionally, if another person who does care for other inits comes along and makes it compatible, I (and, by extension, the module's users) must still be able to configure every aspect of the systemd service without limitations.
Abstractions that make certain common things such as the service's exectuable portable are welcome and (IMO) do not constitute unreasonable complexity but I must still be able to use e.g. systemd's ExecStart with its exact semantics without having to think about other inits' equivalents should there not be an abstract interface for this.

Requiring NixOS maintainers to muck with bash scripts or whatever in order to implement mechanisms for which systemd has a standardised interface would be an absolute no-go for me.

Related to this: If we want alternative inits to have a chance, I think it'd also be a good idea to be able to explicitly declare a service as incompatible. If my module makes use of an init-specific feature and the service's execution is dependant on it, I need to be able to tell the user that my module won't work for them at eval time.
This also goes the other way: If at some point service modules are implemented by non-systemd users making use of non-systemd init features, they must be able to declare their modules incompatible with systemd. (This would also be useful for modules that only make sense on a specific platform.)

If you can achieve that, I'm all for it.

Copy link
Member

@AndersonTorres AndersonTorres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I am very interested in getting rid of systemd dependency, I am very excited about this RFC!

Comment on lines +37 to +39
to Linux, Nix also has first-class support for macOS/Darwin. With some effort,
it can also be used on other UNIX-like operating systems, such as FreeBSD and
Cygwin.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This effort should be better quantified.
Nix repo does have CI jobs only for MacOS and (Ubuntu) Linux only. We don't have a precise measure about how hard is to support FreeBSD or Cygwin.

Further, I am not aware of "portability policies" adopted by Nix source code repo.
Certainly we have the ongoing (and very advanced, I dare to say) #132, but before this I have seen no such attempt of portability as a policy.

Even further, as far as I can remember, the default install of Nix requires some, ehr, post-install service management. And even among Linux distros it is not very portable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

portability as a policy.

It's a policy-free package manager ;)

This kind of thing is more a matter of resources, prioritization (usually by those who have the resources), and a hint of perseverence.

Recently we did merge NixOS/nix#8887 but that's really just a starting point, an empty space for others to contribute and nowhere near a commitment or policy. If someone can seriously help out, please do.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nix does not have an official policy to support other platforms than Linux and macOS/Darwin, but the reason is just simply because of a lack of resources: we don't have manpower and resources (e.g. Hydra build machines) to effectively maintain other ports. On the other hand, Nix does not restrict other platforms and accepts contributions for other platforms.

I myself, for example, have contributed fixes for exotic platforms in several occasions.

If the user base for other platforms grows, then there is little reason to ignore them.

From a historic perspective -- in the early days e.g. 2009-2012 we had all kinds of exotic build machines in our Hydra cluster at Delft University of Technology, such as FreeBSD, OpenBSD and OpenSolaris. Nix could be used on all of these operating systems. Moreover, in the stdenv/ directory of Nixpkgs you can still find traces of code that makes it possible to build stuff on such platforms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a policy-free package manager ;)

Technically, there is RFC #46 for Nixpkgs. But I understood the point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For completeness, it was a reference to the Nix paper, Nix: A Safe and Policy-Free System for Software Deployment, which has nothing to do with support policies. (so an inside joke for those aware of the paper)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, there is RFC #46 for Nixpkgs. But I understood the point.

That RFC is about documentation. Unfortunately the title it chose does not mention that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have https://github.com/nixos-bsd, we know a lot more about this!!

@svanderburg
Copy link
Member Author

(The rendered link is still wrong.)

Ah yes. I've just fixed it!

@CMCDragonkai
Copy link
Member

Does this RFC cover dynamic service orchestration or is that our of scope?

@AndersonTorres
Copy link
Member

If I, as a maintainer for some NixOS module, do not care for other init systems but systemd, I must be able to write the module in such a way that it is only compatible with systemd.

A mandatory non-portable module? Why?

I must still be able to use e.g. systemd's ExecStart with its exact semantics

You want access to systemd the same way the keyword asm provides access to the assembler?

Also, how portable is that systemd interface?

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/duplication-home-manager-and-nixos-modules/30862/28

@svanderburg
Copy link
Member Author

Does this RFC cover dynamic service orchestration or is that our of scope?

What do you exactly mean with "dynamic"? Is it about deploying processes that are not part of a NixOS system profile?

@CMCDragonkai
Copy link
Member

Does this RFC cover dynamic service orchestration or is that our of scope?

What do you exactly mean with "dynamic"? Is it about deploying processes that are not part of a NixOS system profile?

I like to think of first-class orchestrators. One can imagine this system as an orchestrator. If this system deploys an orchestrator as a service, then that results in some level of dynamic orchestration.

@DrRuhe
Copy link

DrRuhe commented Oct 6, 2023

To add a bit of other "prior art", I'd like to mention a project I've been working on recently, which extends the drv-parts(Now part of dream2nix) to define a generic service layer with the module system which can be rendered into configurations for multiple process managers. The project is still in development, but the core module api is pretty much finnished. It allows defining multiple services together in a straightforward way. See this example:

deployments.hello.services = {
      hello = {
        imports = [
          ../packages/hello.nix #uses the hello package defined in a drv-parts/dream2nix module
        ];

        service = {
          args = [
            "-g"
            ''"Hello there, $GENERAL!"'' 
          ];
          env.GENERAL = "General Kenobi";
        };
      };
      other-service = {
        imports = [
          ../packages/hello.nix
        ];
        service.args = [
          "-g"
          ''"Hello from the other service!"''
        ];
      };
    };

Note that this setup could also easily be used without drv-parts/dream2nix, by requiring services to set a "mainProgram" option instead.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfc-0163-portable-service-layer/33886/3

It can also use the Nix process management framework to deploy services that
are managed by any kind process manager supported by the framework.

Aside from the first and last option, the biggest drawback is that these
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not group the "best options" and say "Aside from the last two options..."?

own `process` module that deploys services as daemons running the background.
It can also use the Nix process management framework to deploy services that
are managed by any kind process manager supported by the framework.

Copy link
Member

@Aleksanaa Aleksanaa Oct 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* [NixNG](https://github.com/nix-community/NixNG) is considered a late sibling to NixOS and shares many designs of it. It also implements the function of generating services for several kinds of init systems from the same nix expressions.
* [nixos-init-freedom](https://git.sr.ht/~guido/nixos-init-freedom) puts some efforts on replacing systemd-as-pid-1 with s6. Instead of implementing a generic service layer, it translates parts of systemd module configuration into s6 configuration.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/what-is-the-equivalent-of-configuration-nix-for-just-the-nix-package-manager/34070/2

@ehmry
Copy link

ehmry commented Oct 11, 2023

Excellent. Immediate benefits aside this kind of abstraction would be immensely helpful for OS research.

I'm wondering how far the scope of "services" extends above the system-level. Could graphical desktop applications be included? That's a big scope-creep but I imagine there is more incentive to write fresh desktop services than to migrate NixOS services that already work fine where they are.

I run Synit as a second-level init system and I can't be bothered to rewrite the systemd services from NixOS, but I do write services from-scratch for my desktop environment.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-06-10/46817/1

@deviantsemicolon
Copy link

To clarify, would this allow people to use init systems other than systemd?

@Animeshz
Copy link

@deviantsemicolon NixOS is currently highly dependent on systemd, so there's neither an ETA nor plans to make it replaceable, but surely this will fulfil the usages of nix as a portable package manager and build system -- allowing it to integrate nicely over macos, other linux distribution, ci/cd environments and more. Additionally this will serve as first step in modularising the core that it'd benefit if in case it is ever needed to shift from systemd in the future (highly unlikely though, for now).

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-06-24/47589/1

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/brainstorming-for-rfc-assimilate-home-manager-into-nixpkgs-monorepo/48230/14

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-07-08/48678/1

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/disnix-vs-kubernetes/1902/2

@AndersonTorres
Copy link
Member

To clarify, would this allow people to use init systems other than systemd?

I believe we can be a bit more ambitious and write a distro in this portable service framework.

@KFearsoff
Copy link

Tangentially related, but we could also specify "storage tiers": ephemeral/persistent/essential/cache. That would make impermanence project also a first-class citizen. See also: nix-community/impermanence#10 (comment)

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-08-05/50170/1

@aanderse
Copy link
Member

I believe we can be a bit more ambitious and write a distro in this portable service framework.

@AndersonTorres sounds super fun to prototype - any plans personally to start something like that at some point?

@asymmetric
Copy link
Contributor

RFCSC: There hasn't been much activity here in the last few months, has there been activity through other channels? If so, please provide an update here.

Otherwise, are there any actions you can foresee to take this RFC towards conclusion? If not, feel free to draft this PR.

/cc'ing shepherd team: @AndersonTorres (lead) @roberth @ehmry @Animeshz @IreneKnapp

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-08-19/50831/1

@AndersonTorres
Copy link
Member

I believe we can be a bit more ambitious and write a distro in this portable service framework.

@AndersonTorres sounds super fun to prototype - any plans personally to start something like that at some point?

I have only an Emacs instance and a dream :)

I feel that I need to study more things about Nixpkgs itself. But yes I want to try something, especially testing other init systems.

@aanderse
Copy link
Member

sounds cool - please ping me if you start hacking on something

i am still trying to understand how some of these concepts practically work, though 🤔

let's take the example @roberth provided in NixOS/nixpkgs#267111 - a pragmatic implementation of some ideas Eelco wrote about a long time ago - at first glance the ability to write something like services.foo = <module here> looks great and saves us the security nightmare of a flakes world where we "don't want the PostgreSQL module to have the ability to change your X11 configuration"... but after i play that scenario out in my mind i realize nixos is so awesome because postgres can change my x11 configuration... well not specifically that example, but see any module of a web application which uses a database, redis, web server, etc... if we fully commit to essentially containers this works fine, but i am not sure we want that.

anyone have any thoughts on that?

@SuperSandro2000
Copy link
Member

SuperSandro2000 commented Aug 20, 2024

Tangentially related, but we could also specify "storage tiers": ephemeral/persistent/essential/cache. That would make impermanence project also a first-class citizen. See also: nix-community/impermanence#10 (comment)

IMO for a first implementation this would be kind of feature creep and even more discouraging people to adapt this.

  • emery is using nix-processmgmt with nixos already and is willing to help integrate some form of it in nixpkgs

Some notes from me after looking a bit on a random file:

at first glance the ability to write something like services.foo = looks great and saves us the security nightmare of a flakes world where we "don't want the PostgreSQL module to have the ability to change your X11 configuration"... but after i play that scenario out in my mind i realize nixos is so awesome because postgres can change my x11 configuration... well not specifically that example, but see any module of a web application which uses a database, redis, web server, etc... if we fully commit to essentially containers this works fine, but i am not sure we want that.

Yeah, the module system does not really have concept of security and retrofitting that will end up in usability nightmares.
Instead of using higher level options people will then result to shell scripting to achieve their goals. I can't use tmpfiles.d? I might as well just use mkdir, a ln and hope for the best.

Also any service running with root can change many configuration files and data on the disk even when it can't change the module system. To prevent that we need stronger sandboxing which currently has a strong tie to systemd.


I think we would loose features like easy socket activation.
Also the service managers seem to lack functionality to implement advanced dependency systems like the acme module has, requiring people to probably fall back to polling directories via shell which is exactly where we do not want to go back. That module is also making good use of bind mounts.
I am having a real hard time imagining the acme module in that new service layer abstraction without being a pain to work with and the abstraction being in your way.

@ehmry
Copy link

ehmry commented Aug 21, 2024

FWIW I'm waiting on the delivery of some hardware before I do an init overhaul down to pid1.

I don't like how long this issue has been open without progress but this is an issue we can't ignore completely because it will continue to be brought up. I think init portability will be a bit like maintaining powerpc support in nixpkgs, we don't do it because many people ask for it, we do it because it demonstrates that our basic portability is sound.

@ylh
Copy link

ylh commented Aug 26, 2024

I don't like how long this issue has been open without progress but this is an issue we can't ignore completely because it will continue to be brought up.

yes, what i'm noticing here is much of this thread seems to be less about drafting the rfc per se, and more about the broad issue of abstracting service management, which, hey, fair enough, it's something people evidently care about.

at the risk of perpetuating the trend,

In NixOS, there is no high-level concept of process dependencies. It is still
possible to directly control the activation order by modifying systemd's `Wants=`
and `Requires=` directives through overrides, but this is not really
user-friendly.

it's worth noting that systemd has no high-level concept of dependencies. this bit of docs:

Note that transactions are generated independently of a unit's
state at runtime, hence, for example, if a start job is requested on an
already started unit, it will still generate a transaction and wake up any
inactive dependencies (and cause propagation of other jobs as per the
defined relationships). This is because the enqueued job is at the time of
execution compared to the target unit's state and is marked successful and
complete when both satisfy. However, this job also pulls in other
dependencies due to the defined relationships and thus leads to, in our
our example, start jobs for any of those inactive units getting queued as
well.

serves to illustrate that transactions are related to units by suggestion, nearly by accident. by similar accident, and the collective input of everyone who converged on systemd as a platform (or had it converge upon them), polishing the happy path 99% of users tread, this is usually unnoticeable.

despite nixos's occasional moments butting heads with systemd's concepts (NixOS/nixpkgs#135557, NixOS/nixpkgs#81138, etc.), we largely get by fine even when straining systemd's expectations, thanks to the hermetic nature (closure bloat aside) of nix packaging, the ability to sprinkle tests anywhere in evaluation, generation rollbacks as deep down as the grub menu, etc.

The `dependencies` parameter can be used to automatically generate a
configuration in which the order is preserved. For example, when generating
a `systemd` configuration, this property can be translated into `Wants=` and
`Requires=` directives. For `sysvinit` we can derived sequence numbers.

* `sysvinit` scripts (also known as LSB Init compliant scripts). Because it is
standardize by the LSB, widely used and the most primitive, I have decided to
experiment with this first.

on the complete opposite end, sysvinit offers no more runtime guarantees than any other shell scripts in a trenchcoat, but yes, a boot sequence for it is a fairly trivial function of a partial ordering expressed by dependencies.

so for any sufficiently nice, general definition of a "service" that expresses dependencies and so on: ...accordingly nice, well-designed target platforms to compile down to—that can actually take advantage of all that generality—are thin on the ground.

at that rate, services.kubernetes, virtualisation.oci-containers, and friends join the list of "prior art", which raises a point: many objections in this thread are about portability efforts adding burden to maintaining plain old systemd services. this initiative has the potential to be more qol than bother for nixos proper, though:

  1. right now, if you want to move your systemd.services a level above bare metal without rewriting them, your (in-tree) options are the native systemd-nspawn container module, or building a vm image. some nixos users would be happy to see that list grow.
  2. singleton services, as mentioned, are a pain. putting in my vote for the humble module-level library to aid turning current singleton services instanced, as some have drafted here. such a library would necessarily implement a number of ideas in this rfc. done right it could go over just as uncontroversially as the existence of lib.mkEnableOption.
  3. further down the line, systemd tmpfiles, for instance, could be abstracted out in places, as i've seen those abused to generally ensure the presence of certain directories, where impermanence as mentioned, and, more generally, reifying storage lifetimes, seems more prudent.

what i'm getting at is that after sufficiently many tangentially-related baby steps that make nixos nicer in general, huge swaths of a portable service layer, if not the whole thing, have a chance to fall out for free.

so, if the strongest intersection of opinion is just that having a portable service layer would be Nice™, i could see this rfc getting merged with most of the code samples omitted, as a largely conceptual/advisory piece, to take note of how conducive future nixos changes are to the overall goal, and once a specific implementation feels close at hand, a subsequent rfc detailing it supersedes this one.

ps.

* [home-manager](https://github.com/nix-community/home-manager) offers a service
layer that works with systemd user services, rather than system services. It
contains its own set of service configurations that can be deployed as user
services.

fwiw, home-manager gets by, for the time being, independently specifying launchd and systemd units for a service definition on a can-be-bothered basis, ex. https://github.com/nix-community/home-manager/blob/c2cd2a52e02f1dfa1c88f95abeb89298d46023be/modules/services/nix-gc.nix#L108-L149

thing is, home-manager services tend to be comparatively low-stakes, to the point that taking on an additional channel or flake input for the sake of a user-level service doesn't feel worth it—take it from someone who's running out of memorable 4-digit ports on localhost courtesy solely of nix-darwin.

there is a big difference between i3bar/godoc and nginx/postgres.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-09-02/51514/1

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/how-to-deploy-a-service-on-a-non-nixos/51597/2

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/brainstorm-for-rfc-assimilate-home-manager-into-nixpkgs-monorepo/48230/91

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-09-16/52224/1

@AndersonTorres
Copy link
Member

FWIW I'm waiting on the delivery of some hardware before I do an init overhaul down to pid1.

Any news on this, @ehmry ?

@ehmry
Copy link

ehmry commented Sep 30, 2024

@AndersonTorres I've applied for funding and I'm blocked waiting for a response.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-09-30/53690/1

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/build-docker-images-derived-from-nixos-module/53747/6

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-10-28/55095/1

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/rfcsc-meeting-2024-11-11/55888/1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.