The default bridge
Every Docker host has a few built-in networks. List them:
docker network ls
You'll see at least:
| Network | Driver | What is it? |
|----------|--------|-------------|
| bridge | bridge | The default. Every docker run without --network joins this. Containers can reach the outside via NAT; they can NOT resolve each other by name. |
| host | host | Container shares the host's network namespace. No isolation, no port mapping needed. |
| none | null | No networking at all. |
Inspect the default bridge to see what's connected:
docker network inspect bridge
The Containers array lists every container currently on the
network, with its bridge-local IP (usually 172.17.0.x).
Start two containers on the default bridge and try to talk between
them by name โ it'll fail:
docker run -d --name alpha alpine sleep 600
docker run -d --name beta alpine sleep 600
docker exec alpha sh -c 'ping -c 1 beta || echo "by name: NO"'
beta_ip=$(docker inspect -f '{{.NetworkSettings.IPAddress}}' beta)
docker exec alpha ping -c 1 "$beta_ip" 2>&1 | tail -3
By IP it works. By name it doesn't. That's a deliberate limitation
of the default bridge โ and the main reason you should always create
your own. Click Verify step when alpha and beta are both
running.
Hint
`docker network ls`, `docker network inspect bridge`.
Custom networks and DNS
User-defined bridge networks fix the biggest annoyance with the
default: built-in DNS for container names.
Create one:
docker network create --driver bridge app-net
docker network ls
Start two containers, both attached to app-net:
docker run -d --name api --network app-net alpine sleep 600
docker run -d --name db --network app-net alpine sleep 600
Now talk between them BY NAME โ no IP lookup needed:
docker exec api ping -c 2 db
docker exec api nslookup db
This is what makes microservice topologies practical. Your app
container references the database container as db:5432 and the
runtime resolves it. No service-discovery sidecar required.
Inspect the network to see members:
docker network inspect app-net | jq '.[0].Containers'
Click Verify step once api can ping db by name.
Hint
Containers on the same user-defined bridge resolve each other by name.
Connecting + disconnecting
A container can be on multiple networks simultaneously. Connect a
running container without restarting it:
docker network connect bridge api
docker inspect api --format '{{json .NetworkSettings.Networks}}' | jq
api is now reachable on both networks โ the custom app-net
(where it can resolve db by name) AND the default bridge. This
is how you'd join a "frontend" container to both an isolated backend
network and a public-facing one.
Disconnect:
docker network disconnect bridge api
docker inspect api --format '{{json .NetworkSettings.Networks}}' | jq
Patterns this enables:
- Tiered networks โ
frontend-net, backend-net, db-net. Web
servers join frontend + backend; app servers join backend + db.
- Migrations โ connect to the new network, verify, disconnect
from the old one. Zero restart.
- Sidecars โ observability containers on a
monitoring-net
that's also wired into every other app network.
Click Verify step once api is back on app-net only.
Hint
`docker network connect <net> <container>` joins a running container to another network.
Port mapping in depth
-p is the bridge between the container's port and the host. Five
shapes worth knowing:
-p 8080:80 # host 8080 โ container 80, all interfaces
-p 127.0.0.1:8080:80 # host 8080 โ container 80, ONLY loopback
-p 80 # random host port โ container 80 (look it up with docker port)
-p 8000-8005:8000-8005 # range
-p 8080:80/udp # UDP
Try each:
docker run -d --name pub --network app-net -p 8200:80 nginx:alpine
docker run -d --name priv --network app-net -p 127.0.0.1:8201:80 nginx:alpine
# Both reachable on the host:
curl -sI http://localhost:8200/ | head -1
curl -sI http://localhost:8201/ | head -1
# But only one is reachable on the (sandbox's) external interface:
docker port pub
docker port priv
The pub container is published on all host interfaces; priv
only on 127.0.0.1. In a real-world deploy, ports you only want
behind a reverse proxy on the same host should bind to loopback โ
never expose them publicly by accident.
To enumerate every published port on the host:
docker ps --format 'table {{.Names}}\t{{.Ports}}'
Click Verify step when both pub and priv are responding.
Hint
`-p 8080:80` host:container, `-p 127.0.0.1:8080:80` to bind only loopback.