Skip to content

cli/command/formatter: sort published ports numerically by IP - #7144

Merged
thaJeztah merged 1 commit into
docker:masterfrom
hirehamir:fix/ps-port-sort
Aug 6, 2026
Merged

cli/command/formatter: sort published ports numerically by IP#7144
thaJeztah merged 1 commit into
docker:masterfrom
hirehamir:fix/ps-port-sort

Conversation

@hirehamir

Copy link
Copy Markdown
Contributor

- What I did

Fixed #7143 - docker ps ordering published ports by the string form of the host IP rather than numerically, so 10.0.0.2 was listed before 9.0.0.1.

- How I did it

comparePorts compared IPs with

i.IP.String() < j.IP.String()

PortSummary.IP is a netip.Addr, which provides Less for exactly this purpose, so this uses that instead.

It also avoids formatting both addresses as strings on every comparison.

- How to verify it

docker run -d --name porttest -p 127.0.0.9:8081:80 -p 127.0.0.10:8080:80 nginx:alpine
docker ps --format '{{.Ports}}'

Before: 127.0.0.10:8080->80/tcp, 127.0.0.9:8081->80/tcp
After: 127.0.0.9:8081->80/tcp, 127.0.0.10:8080->80/tcp

A new case in TestDisplayablePorts covers this.

ports before after
64 1540 allocs/op 394 allocs/op
256 5364 allocs/op 1548 allocs/op

That's a ~74% (3.9x) reduction in allocations in Docker CLI's port-sorting path.

- Human readable description for the release notes

Fixed `docker ps` sorting published ports lexicographically instead of numerically.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!


if i.IP != j.IP {
return i.IP.String() < j.IP.String()
return i.IP.Less(j.IP)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wondered why this was there, but looks like previously IP was just a basic string, so when it changed, this was probably used as closest match (f81816e);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I think you're right.

Comment thread cli/command/formatter/container_test.go Outdated
b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit; we can probably use for b.Loop() { now

Comment thread cli/command/formatter/container_test.go Outdated
Comment on lines +976 to +984
func BenchmarkDisplayablePorts(b *testing.B) {
// Every port shares a container port, so
// each comparison falls through to the
// host-IP comparison.
// Descending order keeps the input unsorted.
const (
sharedContainerPort = 80
firstHostPort = 30000
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm a bit on the fence on the benchmark; it's nice, but maybe a bit too much for this code (and mostly we're now benchmarking stdlib).

@vvoland WDYT?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah I don't think it's worth benchmarking

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Okay, I'll remove it right now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! It was useful to show the difference, but probably "too much" for this part of the code.

(appreciate the work! ❤️)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're welcome! And no worries.

`comparePorts` compared host IPs with `i.IP.String() < j.IP.String()`, which
sorts them lexicographically, so "10.0.0.2" ordered before "9.0.0.1" in
`docker ps` output.

This also avoids formatting both addresses as strings on every comparison.

ports    before               after
64       1540 allocs/op       394 allocs/op
256      5364 allocs/op       1548 allocs/op

That's a ~74% (3.9x) reduction in allocations.

Signed-off-by: Hamir <hirehamir@gmail.com>

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks!

@vvoland vvoland added this to the 29.8.0 milestone Aug 6, 2026
@thaJeztah
thaJeztah merged commit 4f84911 into docker:master Aug 6, 2026
98 of 101 checks passed
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.

docker ps sorts IPs lexicographically instead of numerically

4 participants