Proposal: Port Allocations from a Host Range and Host Port Persistence Policies#12622
Proposal: Port Allocations from a Host Range and Host Port Persistence Policies#12622bru7us wants to merge 2 commits intomoby:masterfrom
Conversation
|
FWIW the single test that failed passed on my local run inside the dev container: |
|
I'm curious what the use case for this is. I can't think of any reason why you would want docker to use one dynamic range, and non-docker to use another dynamic range. |
|
I don't think this makes sense as a container configuration. |
|
Actually docker still uses both ranges - the primary use case is for production deployments where the specific port used isn't important, but the port should persist over daemon/host/container restarts because the container is behind a reverse proxy (F5 BIG-IP in my case). Using the "static range" provides this persistence of the port after a restart. Dev and Test containers in our environment would use dynamically allocated, ephemeral ports. The alternative is having some additional 3rd party or custom service that selects and manages ports on all hosts and is injected into the deployment process to select a port on each host at container run time, then run the containers with an explicit port. This is not ideal as Docker already provides a port-selection mechanism. |
|
If you need a static port, why not use a specific port in the |
|
Because then I have to track and manage ports that are in use on every host/service that I deploy, which is something the docker daemon is already doing on my hosts. I don't need the port to be specific, just static. It also doesn't need to be the same port on each host. |
|
@bru7us @icecrime covered why the other PR was closed in #10052 (comment). How does this PR address those points? I could see something where one specifies a port range then upon restart, it grabs a new port from that range. However, having this be sticky after assignment seems problematic. |
|
@stevvooe , my understanding is that the biggest concern with the other PR seemed to be that we were locking up ports from the ephemeral pool (with stopped containers eventually leading to a port exhaustion situation). My proposal addresses that by implicitly leaving the ephemeral range alone and blends the existing features that the daemon provides to:
It also adds the ability to define any port range for a specific container (or group of containers) from which to search and allocate free ports (outside of the standard/system ephemeral range if that's what you need) without forcing you to track and manage those ports via some other means. I feel there's a good balance here because if the container is stopped and another container ends up running with the same port while it's down, the first container would simply fail to restart because the port is in use (exactly the same as current [and expected] behavior when a user explicitly starts with Ultimately, a user would most likely want to have an 'always' restart-policy when using this feature on a container whose port should remain static. Based on numbered point 2 in your last comment on #10052, this solution only every allocates a port once - using this feature doesn't TL;DR: You're not forced to manage port allocation externally, nor to manage stopped containers from locking up ports. This is not "port persistence", rather "one-time port selection from a range at create time". |
|
Note the main concern was not about exhaustion of "the" ephemeral port range but rather any ephemeral port range.
This is the main issue with the proposal. How would one mitigate the failure to restart? Effectively, there is a failure condition on the second start that did not exist in the first start. It seems like it would make more sense to reallocate from the original provided range rather than fail because the container can't rebind the random port it got before. Otherwise, if you need static ports, use static ports. |
|
I hear what you are saying - but I don't think this change introduces any new failure conditions. The use case for this type of interaction is where you really don't care which port is in use (container will be added to pool config on proxy after startup), but once you have the port, it should be sticky. Do you think the proposal would seem more holistic if we re-allocate from the range if the originally selected port is in use on restart? That shouldn't be too significant of a change. |
|
OK, latest commit implements your suggestion. I'd really prefer to be able to dump a warning back to the user/client, but passing any non-nil error looks like it would release the port and bail out... so for now we log a warning if we fall back to a re-allocation situation. I think the documentation update makes it pretty clear on what the expected behavior is when you use the option. We first try to persist the same port, but if it's in use AND we're inside of the custom range for this container, try to allocate a new one. |
|
Alright - after looking at #10052, #12622 (this PR) and #12927, I believe I have conceptualized the solution we're all looking for, which is an effective merge of all 3 proposals and a couple of other tweaks. I haven't started changing code for this yet, but there shouldn't be much more to change other than what is already covered by these 3 PRs. I'd love to get some community feedback on the concept first: A user should be able to provide:
No port will ever be 'consumed' by a stopped container. There should then be a port persistence policy on each container. I really think this covers all of the bases and should also alleviate the concerns that were previously raised. Do you have any thoughts on the matter @stevvooe @icecrime @cezarsa @dkjer ? |
|
@bru7us You have appropriately the described the various behaviors and I do like the way you've mapped them. We may want to work on the terminology "attempt" vs "always", as we could swap the terms and definitions and get the same result. Something like a "soft"-bind vs a "hard"-bind. Also, seems like these options should only apply to dynamic allocations. For example, providing |
Yes, this would only ever apply to dynamic ports, however I think you should still be able to use persistence and static allocations together without error, this should be completely valid: |
|
@bru7us Why not just keep it simple, and use --persist-ports (no =[something])? The default behavior for port ranges could be changed to what you call 'attempt'. When --persist-ports is specified, the only difference for port ranges would be that a busy previously allocated port would cause a failure. |
|
@dkjer There was some earlier discussion and it seemed to be a non-favorable option to have there be an error condition on second start if the port was busy. I figured having a very explicit policy to apply on first start mitigated that somewhat. I'd be happy enough to push forward with the simple flag - if the maintainers buy off. |
|
Right, but changing the default could be breaking for some other use cases. The current default behavior for dynamic allocation is to always re-allocate. |
a2dd75e to
7ddff3d
Compare
|
@stevvooe I've just finished implementation as described above and squashed my commits. I think the updated terminology should be a bit clearer, I went with: Do you think it might be ready for code/doc-review? |
…nce policies Signed-off-by: Dave Russell <bru7us@bru7us.com>
Signed-off-by: Dave Russell <bru7us@bru7us.com>
|
Looks like this code is going to be dead soon due to #13060. |
|
@bru7us It's more critical that we get the design correct first. Rather than have a flag that applies to all of the arguments for the particular persistence type, why not have the argument dictate the behavior. For example, |
|
@stevvooe Agreed - getting the design pinned down and accepted is indeed critical. On your last comment - I have a few questions: |
I'm not sure what you mean here. Could you clarify?
We should not allow overlapping port ranges on the command line.
No. This would be the default behavior for port ranges (this is what we do with |
So the way I understand your suggestion is this: both --port-range=[range] and --persist-ports=[range] would apply to all dynamic bindings on the container (i.e. where no host port is specified). My latest implementation also provided the ability to specify a host range as
When using the argument to define behavior, that makes sense. But if I provided 2 different ranges, how do we decide which range to use for each binding where the host port is not specified? That is, what happens to container port 90 here?: With my last implementation, overlaps actually don't matter because we are still using a single global port-map and a single global persistence policy. You can also use both a specified range AND the ephemeral range if you choose to do so (by specifying host port 0 for ephemeral).
What we do today is equivalent to the "static" bind, which always allocates a new port on every start (for dynamic ports); "soft" tries to use the previous port if previous allocation was dynamic and only re-allocates a new one if the old is busy. |
|
@bru7us Thanks for your contribution, I'm very sorry that this got invalidated by the recent introduction of docker/libnetwork. I suggest you take the discussion on that repo (mentioning the history here). Ping @mavenugo @mrjana @aboch: please give this a look, and eventually give guidance to @bru7us if you feel this is an appreciable addition to libnetwork. |
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
This is the libnetwork portion of work required to define port persistence policies (see moby/moby#12622) Remains backward-compatible with docker/docker master Signed-off-by: Dave Russell <bru7us@bru7us.com>
Inspired by the great work of @cezarsa over in #10052, this PR adds
PortRangeto the container HostConfig and provides the--static-port-rangecommand line argument forcreateandrun.If a range is provided, any published ports without a specified hostPort will be allocated an available host port from the provided range. Once allocated, the port is written to the HostConfig and persists as if the container had been started with
-p X:Y.The change allows a user/sysadmin to define a range of ports on a host exclusively for docker containers to use outside of the standard ephemeral range, but still leaves the ephemeral range available for any other true 'dynamic' allocations when they are desired.