-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
builtins.port: manage dynamic port number allocation in nix #1296
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
Conversation
I think this would be very dangerous, because the port numbers depend on the order of evaluation. How do you intend to deal with this problem? ( |
@bennofs your observation is correct. maybe it could be solved by using the options system: read from |
Thoughts:
|
@copumpkin For |
builtins.portinput1
input2
udevhowever, the same is true for a.nix
b.nix
configuration.nix
when doing
and when changing the imports order of
https://github.com/NixOS/nixos/blob/master/modules/services/hardware/udev.nix#L149 conclusion (so far)the generated files of |
@shlevy what do you think about this? i wonder if |
Can you say a bit more about the use case? It seems to me that dynamically allocated ports (unlike uids/gids) are not generally all that useful because you need the port number to access the service. So it would only be useful for services that are internal to the configuration (e.g. a backend server that sits behind a reverse proxy on the same machine). As others have said, having a global counter is problematic in a purely functional language. This is not necessarily a fatal problem since Nix is a DSL for describing packages and system configurations, not an exercise in purely functional language design. However, it would be problematic if port assignments can change on every The typical functional approach would be to thread a counter through the module system computation (i.e. every function gets a type like BTW, it actually would be possible to allocate ports dynamically and persistently at runtime in a way analogous to how we manage uids/gids, namely by making |
use casethe use-case is automatic reverse proxy configuration:
we are currently building a webserver/webservice abstraction which configures a reverse proxy automatically. a brief introduction is this: https://github.com/nixcloud/minimal-example but it does not contain the reverse proxy at the moment. i plan to merge this code into nixpkgs as soon as possible but there are still problems to be solved before i want anyone to see it. nix is a DSLport numbers only change if one changes the configuration or the order of how configurations are evaluated. module system counteri don't understand how one would implement that. if it is a requirement to have it that way, i will consider it. can you point out which files in nixpkgs to look at? /etc/servicesi always thoguht /etc/services is only used by |
I'm very very skeptical that this is something we want. It doesn't seem to solve a particularly pressing issue and involves some completely non-functional semantics. If you can find a way to make the output solely dependent on the input, I'd be much more inclined to take a loo. |
@shlevy how would you solve the problem? this issue is pressing for us! we have to support a 'dynamic' ammount of webservers. i think i can't make the output soley dependent on the input since this a mutual dependency. i'm quite depressed now as i don't see a way forward. if there is someone who understands the problem more than me, please speak up! maybe using however, using |
One option is to dynamically generate your nix expressions, rather than having your nix expression do dynamic allocation. Perhaps you can use the new
I don't understand what this means. I'm not actually sure I understand your use case completely. |
@shlevy using i was wrong with with using how to use
with
didn't work ;P |
@qknight the udev example does not depend on evaluation order of nix expressions, but it depends on the order of composition of modules. This is a big difference, as the evaluation order can potentially change with each nix release (or does nix have a guaranteed evaluation order?) |
No it doesn't |
thanks everyone for the discussion! |
Doesn't disnix have some sort of construct for this sort of thing? We've talked about it before in other contexts |
The Dynamic Disnix framework (https://github.com/svanderburg/dydisnix) has a port assigner tool that can be used to automatically assign unique port numbers to services in the Disnix services model and facilitates reuse across upgrades. The idea is basically that each service takes a metadata property that indicates whether it needs a port assignment and whether the port assignment needs to be unique to the machine or to the environment. The port assigner tool reads the services model (internally converting it into an XML representation) and composes a Nix expression that contains the port reservations. The services expression can import this ports Nix expression to retrieve the port assignments and do whatever they want with them. To make this stuff work, I did not extend the Nix language -- I just simply read an XML representation of the Disnix service model and I compose a Nix expression from that. One of the limitations of the port assigner tool is that it has been made for Disnix specifically -- it knows how to parse Disnix service models, but it cannot be used, for example, for NixOS configuration expressions. Some time ago, I wrote a blog about the port assignment problem and the solution I implemented: http://sandervanderburg.blogspot.com/2015/07/assigning-port-numbers-to-microservices.html |
RFC: builtins.uniqueIDuniqueID, a builtin to statefully manage ID mappings. the current implementation draft is here: conceptin NixOS we have two domains where unique IDs (integers) are required:
both of these domains have a 'dynamic' property which is hard to modulate in nix. UID/GID scenarioif you create a systemd service with a new user/group (apache-a, apache-a) then NixOS will allocate a new ID () using an activation script:
if one later removes that user/group (apache-a, apache-a) and adds a (foo-a, foo-a) user/group NixOS, via the activation script, will reuse the integer representation:
a side-effect is that one has files with user/group IDs which don't belong to anyone for some time:
but after that user/group ID is reused, the files from a service previously belonging to some other user/group (service) are now incorrectly owned by the newly added service shown for folder port managementat
problemone problem, as also pointed out by sander in https://sandervanderburg.blogspot.de/2015/07/assigning-port-numbers-to-microservices.html, is that if one does not map the but lets see a usage example: usage examplein the framework, we currently work on at nixcloud, we can instantiate a webservice multiple times using
currently the user has to do the port management manually, which is a burden. a nice helper is that we check all proxyOption records for port collisions.
automated port resolvingz.nix
nix-instantiate --eval --strict z.nix
open questionsduring development, the port history was stored in:
but for practical use it should go somewhere else. i'd like to be able to configure the uid/gid/port history storage location. thus, i propose to use either of these:
if the evaluation had the pointer to the previous OS build: what do you think? unix domain socketsfor a while i tried to interconnect the webservices to the reverse-proxy using 'unix domain sockets' which sounds great since it avoids ports but apache does not have support for this. on the other hand: if one uses using
|
…d and others easily
updateseelco mentioned:
and aszlig convinced me we should alter the UID/GID activation script and create a PORTs activation script which would generate a custom @edolstra thanks everyone, closing as this will get a PR for nixpkgs most likely ;-) |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/detect-port-conflicts-in-nixos-services/61589/9 |
RFC
Using
builtins.port "myIdentifierString" one can allocated a dynamic amount of
portsbut still be able to retrieve an assignement given a
identifier`.In the example above
port
would be assigned to50000
and each time thisport
is referenced usingbuiltins.port "my_identifier"
it would return the same number50000
.A different configuration might use
builtins.port "webserver1"
and it would return50001
since"my_identifier"
already uses50000
.This PR still lacks documentation and is meant as a RFC.
Note: I couldn't find a way to express the
builtins.port
property innixpkgs/lib
asnix
does not allow state in functions.[ ] check if this is true:
eval-config.nix
can generate configurations for several VMs butbuiltins.port
is global in the sense that it ignores that distinctive property, acting as a global singleton.