I would like a comparison with runit, which is a very minimal but almost full-fledged init system. I see many similarities: control directories, no declarative dependencies, a similar set of scripts, the same approach to logging. The page mentions runit in passing, and even suggests using the chpst utility from it.
One contrasting feature is parametrized services: several similar processes (like agetty) can be controlled by one service directory; I find it neat.
Another difference is the ability to initiate reboot or shutdown as an action of the same binary (nitroctl).
Last year I decommed our last couple of servers that ran processes configured using runit. It was a sad day. I first learned to write runit services probably about 15 years ago and it was very cool and very understandable and I kind of just thought that's how services worked on linux.
Then I left Linux for about 5 years and, by the time I got back, Systemd had taken over. I heard a few bad things about it, but eventually learned to recognise that so many of those arguments were in such bad faith that I don't even know what the real ones are any more. Currently I run a couple of services on Pi Zeros streaming camera and temperature data from the vivarium of our bearded dragon, and it was so very easy to set them up using systemd. And I could use it to run emacsd on my main OpenSuse desktop. And a google-drive Fuse solution on my work laptop. "having something standard is good, actually", I guess.
The backlash against systemd was twofold. On one hand, when released and thrust upon distros via Gnome, it was quite rough around the edges, which caused both real problems and just understandable irritation. Fifteen years after, the kinks are ironed out, but it was sort of a long time. (Btrfs, released at about the same time, took even longer to stop being imprudent to use in production.)
On the other hand, systemd replaces Unix (sort of like Hurd, but differently). It grabs system init, logging, authentication, DNS, session management, cron, daemon monitoring, socket activation, running containers, etc. In an ideal Red Hat world, I suppose, a bare-metal box should contain a kernel, systemd, podman, IP tools, and maybe sshd and busybox. This is a very anti-Unix, mainframe-like approach, but for a big consulting firm, like Red Hat / IBM, it is very attractive.
Leah Neukirchen is active member of the Void Linux community, I expect a lot of cross-pollination here. It would be really great if she could write up something how to use it for Void.
I've gotten used to runit via Void Linux, and while it does the job of an init system, its UI and documentation leave something to be desired. The way logging is configured in particular was an exercise in frustration the last time I tried to set it up for a service.
I wouldn't mind trying something else that is as simple, but has sane defaults, better documentation, and a more intuitive UI.
I like using systemd but it also doesn't have great documentation either. I often find myself unable to grok things by only reading the official documentation and I have to resort to reading forum posts, other people's blogposts or Stack Overflow. To me documentation isn't good enough until it doesn't need any third party material.
Logging in runit seems simple (I don't remember running into problems), but indeed, the documentation leaves much to be desired. Could be a good thing to contribute to Void Handbook.
I'm always torn when I see anything mentioning running an init system in a container. On one hand, I guess it's good that it's designed with that use case in mind. Mainly, though, I've just seen too many overly complicated things attempted (on greenfield even) inside a single container when they should have instead been designed for kubernetes/cloud/whatever-they-run-on directly and more properly decoupled.
It's probably just one of those "people are going to do it anyway" things. But I'm not sure if it's better to "do it better" and risk spreading the problem, or leave people with older solutions that fail harder.
Yes, application containers should stick to the Unix philosophy of, "do one thing and do it well." But if the thing in your docker container forks for _any_ reason, you should have a real init on PID 1.
There's nothing inherently wrong with containers in the abstract: virtualization is a critical tool in computer science (some might it's difficult to define computer science without a virtual machine). There's not even anything wrong with this "less than a new kernel, more than a new libc" neighborhood.
The broken, ugly, malignant thing is this one godawful implementation Docker and its attic-dwelling Quasimodo cousin docker-compose.yml
It's trivial to slot namespaces (or jails if you also like the finer things BSD) into a sane init system, process id regime, network interface regime: its an exercise in choosing good defaults for all the unshare-adjacent parameters.
But a whole generation of SWEs memorized docker jank instead of Unix, and so now people are emotionally invested in it. You run compose to run docker to get Alpine and a node built on musl.
You can just link node to musl. And if you want a chroot or a new tuntap scope? man unshare.
From my experience in the robotics space, a lot of containers start life as "this used to be a bare metal thing and then we moved it into a container", and with a lot of unstructured RPC going on between processes, there's little benefit in breaking up the processes into separate containers.
Supervisor, runit, systemd, even a tmux session are all popular options for how to run a bunch of stuff in a monolithic "app" container.
My experience in the robotics space is that containers are a way to not know how to put a system together properly. It's the quick equivalent of "I install it on my Ubuntu, then I clone my whole system into a .iso and I call that a distribution". Most of the time distributed without any consideration for the open source licences being part of it.
> Supervisor, runit, systemd, even a tmux session are all popular options for how to run a bunch of stuff in a monolithic "app" container.
Did docker+systemd get fixed at some point? I would be surprised to hear that it was popular given the hoops you had to jump through last time I looked at it
Nitro does not declaratively handle service dependencies, you cannot get a neat graph of them in one command.
You can still request other services to start in your setup script, and expect nitro to wait and retry starting your service when the dependent service is running. To get a nice graph, you can write a simple script using grep. OTOH it's easy to forget to require the shutdown of the dependent services when your service goes down, and there's no way to discover it using a nitro utility.
How does this compare to s6? I recently used it to setup an init system in docker containers & was wondering if nitro would be a good alternative (there's a lot of files I had to setup via s6-overlay that wasn't as intuitive as I would've hoped).
Thanks! Reading some of your other comments, it seems like runit or nitro may not have been a good choice for my usecase? (I'm using dependencies between services so there is a specific order enforced & also logging for 3 different services as well).
You seem to know quite a bit about init systems - for containers in particular do you have some heuristics on which init system would work best for specific usecases?
Yeah we only recently broke it out as a standalone repo/binary, as everyone historically vendored it, so docs will get love soon, but it will be part of the next stagex release built and signed by multiple parties deterministically as stagex/user-nit.
To run it all your need to know is put it in your filesystem as "/init" and then add this to your kernel command line for the binary you want nit to pivot to after bringing the system up:
nit.target=/path/to/binary
That's it. Minimum viable init for single application appliance/embedded linux use cases.
nit and your target binary are the only things you actually need to have in your CPIO root filesystem. Can be empty otherwise.
I am interested in using it as a process supervisor in server docker containers. It is clear that it can be compiled from sources, but something like vuxu.org/nitro/install.sh would be super helpful.
She credits runit and daemontools as inspiration, and it looks extremely similar. I hope that at some point she writes a comparison explaining what Nitro does differently from runit and why.
Any well-known generic word is very likely to already have been used by a bunch of projects, some of them already prominent. By now, the best project name is a pronounceable but unique string, for ease of search engine use. Ironically, "systemd" is a good name in this regard, as are "runit" or even "s6".
I would like a comparison with runit, which is a very minimal but almost full-fledged init system. I see many similarities: control directories, no declarative dependencies, a similar set of scripts, the same approach to logging. The page mentions runit in passing, and even suggests using the chpst utility from it.
One contrasting feature is parametrized services: several similar processes (like agetty) can be controlled by one service directory; I find it neat.
Another difference is the ability to initiate reboot or shutdown as an action of the same binary (nitroctl).
Also, it's a single binary; runit has several.
Last year I decommed our last couple of servers that ran processes configured using runit. It was a sad day. I first learned to write runit services probably about 15 years ago and it was very cool and very understandable and I kind of just thought that's how services worked on linux.
Then I left Linux for about 5 years and, by the time I got back, Systemd had taken over. I heard a few bad things about it, but eventually learned to recognise that so many of those arguments were in such bad faith that I don't even know what the real ones are any more. Currently I run a couple of services on Pi Zeros streaming camera and temperature data from the vivarium of our bearded dragon, and it was so very easy to set them up using systemd. And I could use it to run emacsd on my main OpenSuse desktop. And a google-drive Fuse solution on my work laptop. "having something standard is good, actually", I guess.
The backlash against systemd was twofold. On one hand, when released and thrust upon distros via Gnome, it was quite rough around the edges, which caused both real problems and just understandable irritation. Fifteen years after, the kinks are ironed out, but it was sort of a long time. (Btrfs, released at about the same time, took even longer to stop being imprudent to use in production.)
On the other hand, systemd replaces Unix (sort of like Hurd, but differently). It grabs system init, logging, authentication, DNS, session management, cron, daemon monitoring, socket activation, running containers, etc. In an ideal Red Hat world, I suppose, a bare-metal box should contain a kernel, systemd, podman, IP tools, and maybe sshd and busybox. This is a very anti-Unix, mainframe-like approach, but for a big consulting firm, like Red Hat / IBM, it is very attractive.
2 replies →
Leah Neukirchen is active member of the Void Linux community, I expect a lot of cross-pollination here. It would be really great if she could write up something how to use it for Void.
> no declarative dependencies,
Is that a selling point? Could you explain why?
I've heard plenty of reasons why people find systemd distasteful as an init, but I've not heard much criticism of a declarative design.
I've gotten used to runit via Void Linux, and while it does the job of an init system, its UI and documentation leave something to be desired. The way logging is configured in particular was an exercise in frustration the last time I tried to set it up for a service.
I wouldn't mind trying something else that is as simple, but has sane defaults, better documentation, and a more intuitive UI.
I like using systemd but it also doesn't have great documentation either. I often find myself unable to grok things by only reading the official documentation and I have to resort to reading forum posts, other people's blogposts or Stack Overflow. To me documentation isn't good enough until it doesn't need any third party material.
Logging in runit seems simple (I don't remember running into problems), but indeed, the documentation leaves much to be desired. Could be a good thing to contribute to Void Handbook.
runit doesn't always take care of services it manages in the same way as a proper init . From the man page:
"If runsvdir receives a TERM signal, it exits with 0 immediately"
1 reply →
I'm always torn when I see anything mentioning running an init system in a container. On one hand, I guess it's good that it's designed with that use case in mind. Mainly, though, I've just seen too many overly complicated things attempted (on greenfield even) inside a single container when they should have instead been designed for kubernetes/cloud/whatever-they-run-on directly and more properly decoupled.
It's probably just one of those "people are going to do it anyway" things. But I'm not sure if it's better to "do it better" and risk spreading the problem, or leave people with older solutions that fail harder.
Yes, application containers should stick to the Unix philosophy of, "do one thing and do it well." But if the thing in your docker container forks for _any_ reason, you should have a real init on PID 1.
There's nothing inherently wrong with containers in the abstract: virtualization is a critical tool in computer science (some might it's difficult to define computer science without a virtual machine). There's not even anything wrong with this "less than a new kernel, more than a new libc" neighborhood.
The broken, ugly, malignant thing is this one godawful implementation Docker and its attic-dwelling Quasimodo cousin docker-compose.yml
It's trivial to slot namespaces (or jails if you also like the finer things BSD) into a sane init system, process id regime, network interface regime: its an exercise in choosing good defaults for all the unshare-adjacent parameters.
But a whole generation of SWEs memorized docker jank instead of Unix, and so now people are emotionally invested in it. You run compose to run docker to get Alpine and a node built on musl.
You can just link node to musl. And if you want a chroot or a new tuntap scope? man unshare.
> you should have a real init on PID 1
Got a handy list of those? My colleagues use supervisord and it kinda bugs me. Would love to know if it makes the list.
is there any issue besides the potential zombies? also, why can't the real pid1 do it? it sees all the processes after all.
3 replies →
From my experience in the robotics space, a lot of containers start life as "this used to be a bare metal thing and then we moved it into a container", and with a lot of unstructured RPC going on between processes, there's little benefit in breaking up the processes into separate containers.
Supervisor, runit, systemd, even a tmux session are all popular options for how to run a bunch of stuff in a monolithic "app" container.
My experience in the robotics space is that containers are a way to not know how to put a system together properly. It's the quick equivalent of "I install it on my Ubuntu, then I clone my whole system into a .iso and I call that a distribution". Most of the time distributed without any consideration for the open source licences being part of it.
2 replies →
> Supervisor, runit, systemd, even a tmux session are all popular options for how to run a bunch of stuff in a monolithic "app" container.
Did docker+systemd get fixed at some point? I would be surprised to hear that it was popular given the hoops you had to jump through last time I looked at it
1 reply →
tmux?! Please share your war stories.
2 replies →
I've used several hosting providers that charge by the container - Fly.io and Render and Google Cloud Run.
I often find myself wanting to run more than one process in s container for pricing reasons.
If I my plug my friend and colleague's work, https://nixos.org/manual/nixos/unstable/#modular-services has just landed in Nixpkgs.
This will be a game changer for porting to NixOS to new init systems, and even new kernels.
So, it's good time to be experimenting with things like Nitro here!
It will be interesting to compare this to dinit[1], which is used by chimera-linux.
Giving the readme a brief scan, it doesn't look like it currently handles service dependencies?
[1]: https://github.com/davmac314/dinit
I used dinit in Artix Linux. It is lightweight and impressive (https://artixlinux.org/faq.php)
Nitro does not declaratively handle service dependencies, you cannot get a neat graph of them in one command.
You can still request other services to start in your setup script, and expect nitro to wait and retry starting your service when the dependent service is running. To get a nice graph, you can write a simple script using grep. OTOH it's easy to forget to require the shutdown of the dependent services when your service goes down, and there's no way to discover it using a nitro utility.
Thanks for the info!
The name & function overlap with AWS Nitro is severe:
https://docs.aws.amazon.com/whitepapers/latest/security-desi...
I don't foresee any problems. One is an init system anyone can use and the other one is an internal corporate KVM fork nobody else cares about.
How does this compare to s6? I recently used it to setup an init system in docker containers & was wondering if nitro would be a good alternative (there's a lot of files I had to setup via s6-overlay that wasn't as intuitive as I would've hoped).
S6 is way more complex and rich. Nitro or runit would be simpler alternatives; maybe even https://github.com/krallin/tini.
Thanks! Reading some of your other comments, it seems like runit or nitro may not have been a good choice for my usecase? (I'm using dependencies between services so there is a specific order enforced & also logging for 3 different services as well).
You seem to know quite a bit about init systems - for containers in particular do you have some heuristics on which init system would work best for specific usecases?
1 reply →
At Distrust, we wrote a dead simple init system in rust that is used by a few clients in production with security critical enclave use cases.
<500 lines and uses only the rust standard library to make auditing easy.
https://git.distrust.co/public/nit
Likely neat (33% larger than nit), but the readme only explains how to build it, not its interface or functioning.
Yeah we only recently broke it out as a standalone repo/binary, as everyone historically vendored it, so docs will get love soon, but it will be part of the next stagex release built and signed by multiple parties deterministically as stagex/user-nit.
To run it all your need to know is put it in your filesystem as "/init" and then add this to your kernel command line for the binary you want nit to pivot to after bringing the system up:
nit.target=/path/to/binary
That's it. Minimum viable init for single application appliance/embedded linux use cases.
nit and your target binary are the only things you actually need to have in your CPIO root filesystem. Can be empty otherwise.
3 replies →
I am interested in using it as a process supervisor in server docker containers. It is clear that it can be compiled from sources, but something like vuxu.org/nitro/install.sh would be super helpful.
love to see new init projects. how does it stack up against runit (the last one i really familiarized myself with on void linux)?
She credits runit and daemontools as inspiration, and it looks extremely similar. I hope that at some point she writes a comparison explaining what Nitro does differently from runit and why.
runit doesn't propagate SIGTERM to services it starts.
2 replies →
Bring back the init wars! /S
Username relevant...
I got into Linux right before the init wars, and while they were hectic times they brought a lot of attention, discussions, and options to Linux.
[dead]
[dead]
I'd recommend changing names, nitro is already a semi-popular server engine for node.js https://nitro.build/
Any well-known generic word is very likely to already have been used by a bunch of projects, some of them already prominent. By now, the best project name is a pronounceable but unique string, for ease of search engine use. Ironically, "systemd" is a good name in this regard, as are "runit" or even "s6".
I use tiny init systems regularly in AWS Nitro Enclaves. Having the enclave and init system both named nitro is not ideal.
1 reply →
> Any well-known generic word is very likely to already have been used by a bunch of projects,
Are you sure? There are lots of words, and not so many projects that use words like these as their names.
Of the 118179 packages I see on this Ubuntu 18.04 system I can roughly roughly ask how many have names that are dictionary (wamerican) words:
This gives 820 (or about 1000 if you allow uppercase). Not so scientific, but I think a reasonable starting point.
nitronit obviuously