A mental model for Docker networks: how containers find each other, when to publish ports, and the difference between expose and ports.

The mental model: networks are virtual switches

Almost every Docker networking confusion dissolves with one picture: a user-defined bridge network is a virtual switch. Containers attached to it get a private IP and, crucially, a DNS name equal to their container or service name, resolved by Docker’s embedded DNS server. Containers on the same switch reach each other by name on any port; containers on different switches cannot see each other at all; and the host only reaches containers through explicitly published ports.

The "user-defined" qualifier matters: the legacy default bridge (what you get with a bare docker run) does not provide DNS between containers. Always create and use named networks, compose does this automatically per project.

ports vs expose, settled