Skip to content

daemon: return port-mappings from all endpoints #49657

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

Merged
merged 3 commits into from
Mar 18, 2025

Conversation

akerouanton
Copy link
Member

@akerouanton akerouanton commented Mar 18, 2025

- What I did

First two commits are small refactorings.

The third commit addresses the issue described in #49654.

daemon: remove redundant call to getEndpointPortMapInfo

daemon: getEndpointPortMapInfo: err is never used

daemon: return port-mappings from all endpoints

With improved IPv6 support, a dual-stack container can map a port using two different networks -- one IPv4-only, the other IPv6-only.

The daemon was updating containers' EndpointSettings.Ports by looking for the first network providing port-mappings. This was incorrect.

Instead, iterate over the whole list of endpoints, and merge everything together.

The function doing that, ie. getEndpointPortMapInfo, is also considered exposed ports, and nil the PortMap entry if an exposed port is found. However, exposed ports are always set on a bridge network, so this was erasing port-mappings found for other networks. Instead, do not consider exposed ports unless the current network is the default bridge.

- How to verify it

A new integration test is added.

- Human readable description for the release notes

Fix a bug causing `docker ps` to inconsistently report dual-stack port mappings

The function `getEndpointPortMapInfo` is called by `updateJoinInfo` to
update the field `NetworkSettings.Ports` of a container.

However, `updateJoinInfo` is only called by `connectToNetwork` which is
also calling `getPortMapInfo` (which in turn calls
`getEndpointPortMapInfo`).

So, remove the call to `getEndpointPortMapInfo` from `updateJoinInfo`.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Copy link
Contributor

@vvoland vvoland left a comment

Choose a reason for hiding this comment

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

changelog suggestion:

Fix a bug causing `docker ps` to inconsistently report dual-stack port mappings

@akerouanton akerouanton force-pushed the fix-missing-port-mappings branch from 26e8aad to fa124ab Compare March 18, 2025 16:03
natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
if err != nil {
return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
if containertypes.NetworkMode(ep.Network()).IsBridge() {
Copy link
Member Author

Choose a reason for hiding this comment

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

To be honest, I feel like this is a bit crappy as this is going to cause issues when we'll add support for DNS-based links to custom networks. But this is the shortest path to get this bug fixed in v28.0.2.

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add some TODO comment? 🙈

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… I think one part of the problem here is that we're using a single variable to report two distinct concepts (ie. 'exposed ports' and 'published ports').

Currently you can't connect a container to the default bridge and to a custom network, so a container can't have port-mappings provided by two networks and legacy links at the same time.

But once we have DNS-based links available, this will become possible and we'll realize that 'exposed ports' should be an endpoint property. So, maybe it's not worth adding a TODO for a block of code which will be deleted without getting fixed?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think only creating the entry if there's not already a mapping would preserve the existing behaviour for this patch release? ...

if _, ok := pm[natPort]; !ok {
   pm[natPort] = nil
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@akerouanton akerouanton requested a review from vvoland March 18, 2025 16:10
@akerouanton akerouanton force-pushed the fix-missing-port-mappings branch from fa124ab to 4d62124 Compare March 18, 2025 16:11
@akerouanton akerouanton force-pushed the fix-missing-port-mappings branch 2 times, most recently from 0e22e8a to adba758 Compare March 18, 2025 16:37
Copy link
Contributor

@robmry robmry left a comment

Choose a reason for hiding this comment

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

LGTM, although ...

defer network.RemoveNoError(ctx, t, apiClient, nwV6)

ctrID := ctr.Run(ctx, t, apiClient,
ctr.WithExposedPorts("80/tcp"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Could add another exposed port with no host port mapping, to check it shows up?

@akerouanton akerouanton force-pushed the fix-missing-port-mappings branch from adba758 to cef6b95 Compare March 18, 2025 16:49
Instead, log the error returned by `nat.NewPort` and move on to the
next port mapping / exposed port.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
With improved IPv6 support, a dual-stack container can map a port using
two different networks -- one IPv4-only, the other IPv6-only.

The daemon was updating containers' `EndpointSettings.Ports` by looking
for the first network providing port-mappings. This was incorrect.

Instead, iterate over the whole list of endpoints, and merge everything
together.

The function doing that, ie. `getEndpointPortMapInfo`, is also
considered exposed ports, and nil the PortMap entry if an exposed port
is found. However, exposed ports are always set on a bridge network, so
this was erasing port-mappings found for other networks.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
@akerouanton akerouanton force-pushed the fix-missing-port-mappings branch from cef6b95 to f2a183a Compare March 18, 2025 17:13
Copy link
Contributor

@vvoland vvoland left a comment

Choose a reason for hiding this comment

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

LGTM

@vvoland vvoland merged commit 97ee08e into moby:master Mar 18, 2025
149 checks passed
@akerouanton akerouanton deleted the fix-missing-port-mappings branch March 18, 2025 19:48
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.

Inconsistent reporting of dual-stack port-mappings in docker ps
3 participants