Chapter 10 of 16 · Visual guide

Networking: default bridge and veth pairs

The default bridge is a virtual switch on your host. Containers plug into it with virtual cables called veth pairs.

key idea / Docker itselfcontainer / good pathhost / watch outproblem / blockedneutral

The picture to remember

The default bridge networkTwo containers each have an eth0 connected by a veth pair to docker0, a virtual switch on the host. The host eth0 connects docker0 to the internet through NAT.InternetDocker hosthost eth0192.168.1.20NAT / routingdocker0 bridge 172.17.0.1a virtual switch: forwards by MAC addressContainer Aeth0 172.17.0.2veth pair (vethA)Container Beth0 172.17.0.3veth pair (vethB)
docker0 is a virtual switch. Each veth pair is the cable between a container and that switch.

A packet from A to B

A packet from A to BA eth0172.17.0.2vethAhost enddocker0looks up B's MACvethBhost endB eth0172.17.0.3
The bridge is a layer-2 switch, so it forwards on MAC address: no routing needed.

The big downside

The default bridge cannot resolve namesOn the default bridge, pinging a container by name fails. Pinging by IP works, but IPs change when containers restart.By nameb172.17.0.3ping aa ?no DNSbad address "a"By IPb172.17.0.3ping .2a172.17.0.2works, until a restarts and gets .4Fix: use a user-defined bridge, where Docker DNS resolves names (chapter 12)

See it yourself

On Linux. On Docker Desktop these live inside the Linux VM.

Run thisIt shows
ip addr show docker0the bridge and its IP (172.17.0.1)
ip linkone vethXXXX per running container
docker inspect -f '{{.NetworkSettings.IPAddress}}' athe container's address on the bridge
docker exec b ip routedefault via 172.17.0.1: the gateway is docker0

Try it yourself

  1. Step 1 · Two containers on the default bridge

    Leaving off --network attaches them to bridge (docker0).

    $ docker run -d --name a --rm alpine:3.20 sleep 300
    $ docker run -d --name b --rm alpine:3.20 sleep 300
    $ docker inspect -f '{{.NetworkSettings.IPAddress}}' a
    172.17.0.2
    $ docker inspect -f '{{.NetworkSettings.IPAddress}}' b
    172.17.0.3
  2. Step 2 · Ping the IP

    The bridge forwards that packet. The gateway 172.17.0.1 is docker0.

    $ docker exec b ping -c 1 172.17.0.2
    64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.1 ms
    $ docker exec b apk add --no-cache iproute2
    $ docker exec b ip route
    default via 172.17.0.1 dev eth0
  3. Step 3 · The name does not resolve
    $ docker exec b ping -c 1 a
    ping: bad address 'a'
    $ docker stop a b

Recap

Quick check

Why is hard-coding 172.17.0.2 a bad idea?
Show answer

Addresses are assigned at start. After a restart the container may get a different one, and the old address points to nothing or to a different container.