I feel like we're talking right past each other or something.

Of course every TCP [0] and UDP networking system ever has port numbers. And basically every CPU has calls functions with numeric addresses. And you plug in power cables to use a computer. Of course Docker containers internally use ports -- if I have a Docker image plus its associated configuration, and I instantiate it as a container, and it uses its internal port 8080 to expose HTTP, then it uses a port number.

But this whole conversation is about Docker's tooling, not about the underlying concept of containers.

And almost every system out there that has decent tooling has abstraction layers to make this nicer. In AT&T assembly language, I can type:

1:
... code goes here

and that code is called "1" in that file and is inaccessible from outside. If I want to call it from outside, I type something more like:

name_of_function:
... code goes here

with maybe a .globl to go along with it. And I call it by typing a name. And that call still calls the numeric address of that function.

If I plug in a power cable to use a computer, I do not plug it into port 3 on the back of the computer, such that accidentally plugging it into port 2 will blow a fuse. I plug it into a port that has a specific shape and possibly a label.

So, yes, I know that "If an app inside a container is listening on port 5000, but you want to access it on port 8000, you must declare that mapping (-p 8000:5000)", but that's not a good thing. Of course, if it's listening on port 5000, I need to map 8000 to 5000. But the fact that I had to type -p 8000:5000 is what's broken. The abstraction layer is missing. That should have been -p 8000:http or something similar.

And the really weird thing is that the team that designed Dockerfile seemed to have an actual inkling that something was needed here, which is why we have:

EXPOSE 8080
VOLUME ["/mnt/my_data"]

but they completely missed the variant that would have been good:

EXPOSE 8080 "rest_http"
VOLUME "mydata" MANDATORY
MOUNT_VOLUME "mydata" "/mnt_mydata"

or whatever other spelling of the same concept would have passed muster.

And yes, Docker Compose helps, but that's at the wrong layer. Docker Compose is a consumer of a container image. The mapping from logical exposed service to internal port should have been handled at an abstraction layer below Docker Compose, and Compose and Quadlet and Kubernetes and the command line could all share that abstraction layer.

> ... service discovery. You can use docker run -p 8000:80 or define a Docker network where containers resolve each other by name. You already don’t have to care about internal ports inside a proper Docker setup

Can you point me at some relevant reference? Because, both in my experience and from (re-)reading the basic docs, all of the above is about finding an IP address by which to communicate with a relevant service, not about port numbers, let alone internal port numbers (which are entirely useless to discover from inside another container, because you can't use them there anyway). Even Docker Swarm does things like:

$ docker service create ... --publish published=8080,target=80

and that's another site, external to the container image in question, where one must type in the correct internal port number.

> I'm sure you get all sorts of riled up when you need to put an address on a blank envelope because the mail should just know... Right? o_O

I will take this the most charitable way I can. Sure, it's mildly annoying that you have to use someone numerical phone number to call them, and we all have contact lists to work around this, but that's still missing the target. I'm not complaining about how you address a docker container, and it makes quite a bit of sense that you need someone's phone number to call them. But if you had to also know that that particular phone you were calling had its microphone on port 83 and you had you tell your phone that their microphone was port 83 if you wanted to hear them and you had to change your contact list if they changed phone models, then I think everyone would be rightly annoyed.

So I stand by my assertion: Docker's tooling is not very good.

[0] But not every networking protocol ever. Even in the space of non-obsolete protocols, IP itself has no port numbers. And the use of a tuple (name or IP, port) is actually a perennial source of annoyance, and people try to improve it periodically, for example with RFC 2782 SRV records and, much more recently, RFC 9460 SVCB and HTTPS records. This is mostly off-topic, as these are about externally visible ports, and I’m talking about internal port numbers.