← all posts

How Docker containers talk to each other

How does a container reach another container, the host, or the internet underneath? What actually carries the packets?

I had used Docker for years without asking how a packet actually gets from one container to another. docker run -p 8080:80 just worked. One day I realised that if it stopped working, I would not even know where to start looking. So I went back to basics.

What I found

Docker builds container networking from ordinary Linux pieces:

  • Network namespaces: each container gets its own network stack (interfaces, routes, iptables).
  • veth pairs: a virtual cable. One end is eth0 inside the container, the other end sits on the host.
  • A Linux bridge (docker0, or one per user-defined network): the host ends of the veth pairs plug into it, like a switch.
  • iptables NAT: MASQUERADE for outbound traffic, DNAT for published ports.
  • Embedded DNS at 127.0.0.11 on user-defined networks, so containers can reach each other by name.
 container A (172.18.0.2)        container B (172.18.0.3)
       eth0                             eth0
        │ veth                          │ veth
 ───────┴────────── br-xxxx (bridge) ───┴───────
                         │
                   host routing + iptables
                         │  MASQUERADE
                       eth0 → internet

The three paths

from → to how
container → container (same network) layer 2 over the bridge; name resolved by Docker’s DNS
container → internet default route via the bridge IP, then source NAT (MASQUERADE) on the host
internet → container -p creates a DNAT rule; this is why UFW doesn’t see it

The default bridge network has no DNS by name. That’s the main reason to always create user-defined networks (Compose does this for you).

See it on a host

docker network create demo
docker run -d --name a --network demo nginx
ip link show type bridge
ip link show type veth
sudo nsenter -t $(docker inspect -f '{{.State.Pid}}' a) -n ip addr
sudo iptables -t nat -S POSTROUTING

What I still want to try

  • host, none, macvlan and overlay drivers: when to use each
  • How Docker Swarm / Kubernetes CNIs extend this across hosts (VXLAN)
  • Trace a packet with tcpdump on the veth and the bridge

References

Discussion

Enjoy!