In short: the process inside the container must bind to 0.0.0.0 to be reachable from outside the container at all; but you can then use Docker Compose's ports:
option to control where it's actually reachable from. If you change it to "127.0.0.1:8000:8000"
it will not be reachable from off-host.
Docker containers run in an isolated network. A typical setup might look like this:
^^^
Router
| 192.168.1.1
+--------------------+-- ...
| 192.168.1.2 | 192.168.1.3
/- Host -----------\ Host 2
| 172.17.0.1 |
| | |
| | 172.17.0.2 |
| Container |
\------------------/
As an implementation detail each container has its own private IP address. This is on an isolated network: the second host on 192.168.1.3/24 doesn't have any idea that the container-private network on 172.17.0.0/16 even exists much less how to route traffic there. Since each container has its own private network stack, each container also has its own notion of what localhost
means.
(Compare this diagram to a server running directly on the host. It's reachable on 192.168.1.2, but only from the same network; a client on the far side of the router can't reach the 192.168.1.0/24 private network, and again the server is unreachable from the public Internet even if it's bound to "all interfaces".)
If you set the container process to bind only to 127.0.0.1, its own lo0 interface, it will not accept inbound traffic from the 172.17.0.2 eth0 interface, which means that nothing from the outside can ever reach it.
If you set the container process to bind to 0.0.0.0 ("all interfaces"), then it will accept traffic from the host, sending from 172.17.0.1 (probably a docker0 interface). That's not the same as accepting traffic from "the whole network", though: as previously discussed, host 2 still doesn't know how to route traffic there.
You can use the docker run -p
or the Docker Compose ports:
option to limit which interfaces Docker will publish ports to. If you change ports:
to "127.0.0.1:8000:8000"
then the container will be reachable from port 8000 on the host, but only via the host's loopback interface; again, there is no route for host 2 to send packets to the process.