How do Docker bridge, overlay, and macvlan networks handle packets differently, and when should you pick each?
Quick Answer
Bridge uses Linux bridge devices and iptables NAT for single-host containers. Overlay uses VXLAN encapsulation to span multiple hosts. Macvlan gives containers real MAC addresses for direct Layer 2 network access. Pick bridge for single-host dev, overlay for multi-host orchestrated services, and macvlan for legacy apps needing containers on the physical network.
Detailed Answer
Think of three ways to connect apartments in different buildings. A bridge network is like an intercom system inside one building. Residents can talk to each other, and a doorman routes calls to the outside. An overlay network is like a private phone system across multiple buildings, where calls are tunneled through the public phone lines but feel like internal calls. A macvlan network gives each apartment its own front door on the street. No doorman, no intercom, each unit is directly reachable by anyone walking by.
Docker bridge networking creates a Linux bridge device (docker0 or a custom bridge) on the host. Containers attach to this bridge via veth pairs, which are virtual ethernet cables with one end in the container's network namespace and the other on the bridge. The host uses iptables MASQUERADE rules to NAT outbound container traffic through the host's IP, and DNAT rules to forward published ports to container IPs. DNS resolution between containers on user-defined bridges uses Docker's embedded DNS server at 127.0.0.11.
Overlay networking adds VXLAN encapsulation so containers on different hosts can talk as if they are on the same Layer 2 network. Each host gets a VTEP (VXLAN Tunnel Endpoint) that wraps container-to-container frames in UDP packets (default port 4789) addressed to the remote host's IP. A distributed key-value store (Swarm's built-in Raft store or an external one) keeps the mapping of container IPs to host IPs. When container A on host 1 sends a packet to container B on host 2, the local VTEP wraps the frame in a VXLAN header, sends it as a UDP packet to host 2's VTEP, which unwraps it and delivers it to container B. This adds about 50 bytes of overhead per packet and introduces some encapsulation latency.
At production scale, the choice depends on network needs. Bridge is the default and works for single-host deployments or development, but does not span hosts. Overlay is standard for Docker Swarm and works for services needing multi-host communication with network isolation, but VXLAN encapsulation reduces MTU (from 1500 to about 1450) and adds CPU overhead. Macvlan is essential when containers must appear as physical devices on the network, for example a legacy payments-gateway that needs a static IP on the corporate VLAN, or network appliance containers that need promiscuous mode access. Macvlan has near-native network performance because there is no NAT or encapsulation, but containers cannot communicate with the host directly (a common surprise) and DHCP integration requires careful subnet planning.
The non-obvious gotcha with overlay networks is that the VXLAN UDP port (4789) must be open between all hosts, and some cloud security groups block it by default. With macvlan, the host itself cannot reach macvlan containers because the host NIC filters traffic to its own MAC address. You need a macvlan sub-interface on the host to talk to its own containers. Bridge networks have a subtle DNS issue: the default bridge (docker0) does not provide automatic DNS resolution between containers. Only user-defined bridges do, which catches teams that never created a custom network.