The Default Bridge Network
How the default bridge works
Section titled “How the default bridge works”When the Docker daemon starts, it creates a virtual Ethernet switch called docker0 on the host. This is the default bridge network. Every container that you start without specifying --network is connected to docker0 automatically.
Containers on the default bridge receive an IP address from the 172.17.0.0/16 subnet. The gateway — and the host itself — sits at 172.17.0.1.
flowchart TB host["Host"] bridge["docker0 (172.17.0.1)"] c1["container c1 (172.17.0.2)"] c2["container c2 (172.17.0.3)"] host --> bridge bridge --> c1 bridge --> c2
Running two containers and inspecting their IPs
Section titled “Running two containers and inspecting their IPs”Start an nginx container named c1 and an Alpine container named c2:
docker run -d --name c1 nginx:alpinedocker run -d --name c2 alpine sleep 300Inspect the IP address assigned to each container:
docker inspect c1 --format '{{.NetworkSettings.Networks.bridge.IPAddress}}'docker inspect c2 --format '{{.NetworkSettings.Networks.bridge.IPAddress}}'You will see addresses like 172.17.0.2 and 172.17.0.3.
Containers can ping each other by IP
Section titled “Containers can ping each other by IP”Because both containers are on the same docker0 bridge, layer-3 routing between them works. From c2, ping c1 by its IP address:
docker exec c2 ping -c 3 172.17.0.2The ping succeeds. Traffic flows through docker0 on the host.
Container name resolution does NOT work on the default bridge
Section titled “Container name resolution does NOT work on the default bridge”Now try the same ping using the container name instead of the IP:
docker exec c2 ping c1This fails with bad address 'c1' or a similar DNS error. The default bridge network does not include an embedded DNS resolver, so container names are not resolvable. Only user-defined networks (covered in the next lesson) provide automatic DNS.
Cleanup
Section titled “Cleanup”Stop and remove both containers when you are done:
docker stop c1 c2docker rm c1 c2Hands-on: bridge IP inspection
Section titled “Hands-on: bridge IP inspection”# Start two containers on the default bridge
docker run -d --name c1 alpine sleep 300
docker run -d --name c2 alpine sleep 300
# Find their IPs
C1_IP=$(docker inspect c1 --format '{{.NetworkSettings.Networks.bridge.IPAddress}}')
C2_IP=$(docker inspect c2 --format '{{.NetworkSettings.Networks.bridge.IPAddress}}')
echo "c1 IP: $C1_IP"
echo "c2 IP: $C2_IP"
# Ping c2 from c1 by IP (succeeds)
docker exec c1 ping -c 3 $C2_IP
# Try to ping by name (fails — no DNS on default bridge)
docker exec c1 ping -c 1 c2 || echo "Name resolution failed as expected"
# Cleanup
docker stop c1 c2 && docker rm c1 c2Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
Default bridge (docker0) | Works immediately with no extra setup | No built-in DNS resolver — you connect purely by IP address |
| User-defined bridge network | Has an embedded DNS resolver, resolves container names immediately | Needs an extra docker network create step before use |
| Host network mode | Highest performance, no NAT overhead between container and host | No network isolation from the host at all — the container shares the host’s network stack directly |
Common mistakes
Section titled “Common mistakes”- Hardcoding an IP address from
docker inspectinto config, assuming it stays fixed, when it can change the moment the container is restarted or recreated. - Continuing to use the default bridge and then trying to ping a container by name, not realizing the default bridge has no DNS resolver to use.
- Dumping containers from multiple projects onto the same default bridge without separating them, so every container can see and reach every other one without meaning to.
💡 Real-world example
GitLab CI and Jenkins running the Docker executor create a separate bridge network per job instead of using the default bridge, so the main container and its service containers (like a test database) can resolve each other by DNS without colliding with other jobs running in parallel on the same runner.