Most people never create a network and mostly get away with it. Here is where that stops working.
The default bridge has no DNS
Containers on the default
Compose creates a network per project automatically, which is why you rarely think about this until you are debugging a container that cannot find its database by hostname.
Segmentation is the real reason to care
On a server with multiple stacks, one network per stack means stack A's application cannot reach stack B's database, even though both are on the same host. Without that, everything can talk to everything, and one compromised container has a much more interesting afternoon.
Put each customer's stack on its own network. It costs nothing and it is the cheapest lateral-movement control available.
Host networking
The debugging command worth memorising
Which containers are on this network, and at which addresses. Answers most "why can't A reach B" questions in one line.
The default bridge has no DNS
Containers on the default
bridge network cannot resolve each other by name. On a user-defined network they can, and that single difference is why almost every Compose file works and so many hand-run docker run setups do not.
Code:
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name app --network appnet myapp:1.0
# inside app, "db" now resolves
Compose creates a network per project automatically, which is why you rarely think about this until you are debugging a container that cannot find its database by hostname.
Segmentation is the real reason to care
On a server with multiple stacks, one network per stack means stack A's application cannot reach stack B's database, even though both are on the same host. Without that, everything can talk to everything, and one compromised container has a much more interesting afternoon.
Code:
docker network create client-a
docker network create client-b
Put each customer's stack on its own network. It costs nothing and it is the cheapest lateral-movement control available.
Host networking
--network host removes the network namespace entirely — the container shares the host stack. Occasionally necessary for things doing service discovery or handling many ports. Understand what you are giving up: no port mapping, no isolation, and the container binds directly to host interfaces including ones you did not intend.The debugging command worth memorising
Code:
docker network inspect appnet --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
Which containers are on this network, and at which addresses. Answers most "why can't A reach B" questions in one line.