Container DNS and User-Defined Networks
The problem: no DNS on the default bridge
Section titled “The problem: no DNS on the default bridge”As you saw in the previous lesson, containers on the default bridge can reach each other by IP address but not by name. This is a significant limitation in practice — IP addresses are dynamic and change every time a container is recreated.
Hardcoding IP addresses into application configuration is fragile. You need a way to refer to services by a stable name. Docker’s official networking docs are explicit about this split: containers on the default bridge only get a copy of the host’s /etc/resolv.conf, while containers on a custom (user-defined) network use Docker’s embedded DNS server at 127.0.0.11 (docs.docker.com/engine/network). User-defined networks are exactly how you get that stable, name-based addressing.
The solution: create a user-defined bridge
Section titled “The solution: create a user-defined bridge”Use docker network create to create a named bridge network:
docker network create appnetDocker creates a new bridge (separate from docker0) and starts an embedded DNS resolver scoped to that network. Containers attached to appnet can resolve each other’s names automatically.
Running containers on a user-defined network
Section titled “Running containers on a user-defined network”Use the --network flag to attach a container to appnet when you run it:
docker run -d --name web --network appnet nginx:alpinedocker run -d --name client --network appnet alpine sleep 300Both containers are now on appnet, served by Docker’s DNS resolver.
Pinging by container name
Section titled “Pinging by container name”From client, ping web by name:
docker exec client ping -c 3 webThe ping succeeds! Docker’s DNS resolver translates the name web to that container’s IP address automatically.
Inspecting the network
Section titled “Inspecting the network”From the host, inspect appnet to see which containers are attached and what IPs they were assigned:
docker network inspect appnetThe output includes a Containers section listing each attached container with its name, IP, and MAC address.
Teardown
Section titled “Teardown”docker stop web clientdocker rm web clientdocker network rm appnetHands-on: DNS on a user-defined network
Section titled “Hands-on: DNS on a user-defined network”# Create a user-defined bridge network
docker network create appnet
# Start an nginx container on appnet
docker run -d --name web --network appnet nginx:alpine
# Start a client container on appnet and ping web by name
docker run --rm --name client --network appnet alpine ping -c 3 web
# Inspect the network to see attached containers
docker network inspect appnet
# Cleanup
docker stop web && docker rm web
docker network rm appnetTrade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
| Connecting by IP address | No dependency on a DNS resolver | Have to re-query the IP every time the container restarts, since it can change |
| Connecting by container name (DNS) | Name resolves to IP automatically, keeps working even if the IP changes | Only works on a user-defined network — does not work on the default bridge |
Common mistakes
Section titled “Common mistakes”- Hardcoding a container’s IP address into code or environment variables instead of using its container name as a DNS name, breaking the moment the container is recreated with a different IP.
- Expecting DNS resolution to work on the default bridge network, when Docker’s embedded DNS resolver only serves user-defined networks.
- Forgetting that containers must be on the same user-defined network to resolve each other’s names — being on two different user-defined networks does not work either.
💡 Real-world example
In
docker-compose.yml, a service’s name is already a DNS hostname — awebservice can reach a database directly withdb:5432without ever knowing its IP, because Compose creates a user-defined network automatically and registers every service’s DNS name on it.