Docker DNS Fails on Default Bridge — Fix Name Resolution
Docker's default bridge network silently breaks DNS between containers.
- Each container gets its own network namespace (isolated network stack)
- Virtual Ethernet (veth) pairs connect the container namespace to a Linux bridge
- iptables rules handle NAT for port publishing and inter-network routing
- Docker's embedded DNS (127.0.0.11) resolves service names to container IPs
- bridge: default, single-host, private virtual switch
- overlay: multi-host via VXLAN tunnels (Swarm, Kubernetes)
- macvlan: container gets a MAC address on the physical network
- host: no isolation, container shares host network stack
- none: no networking at all
Imagine a massive apartment building. Every apartment (container) has its own front door and lock, but they all share the same physical plumbing and hallways (the host OS). Docker networking is the system that decides which apartments can knock on each other's doors, which ones can receive visitors from the street (the internet), and which ones are completely sealed off from everyone else. Just like a building manager hands out intercom codes and assigns floors, Docker's networking layer assigns IP addresses, creates virtual hallways between containers, and controls who can talk to whom — all without tenants (apps) needing to know any of the details.
Docker networking failures are the most common source of production outages involving containers. When containers cannot reach each other, when DNS resolution silently fails, when latency spikes for no obvious reason — these are predictable consequences of decisions made at the kernel level that most engineers never inspect because 'it just worked in dev.'
Docker networking solves a hard problem: giving hundreds of isolated processes their own private network stack while still allowing controlled, performant communication with each other and the outside world. The answer involves Linux network namespaces, virtual Ethernet pairs, iptables chains, overlay tunnels, and a pluggable driver architecture — all wired together transparently on every docker run.
Common misconceptions: the default bridge network supports service name DNS (it does not — only custom bridge networks do), port publishing is required for container-to-container communication (it is not — containers on the same network communicate directly via container port), and overlay networks have zero overhead (they add VXLAN encapsulation latency). Understanding these distinctions prevents hours of debugging.
CNM Architecture — How Docker Networking Is Organized
Docker networking is built on the Container Network Model (CNM), which defines three abstractions: sandboxes, endpoints, and networks.
Sandbox: An isolated network stack for a container. Created when a container starts. Contains the container's interfaces, routes, and DNS config. Maps to a Linux network namespace.
Endpoint: A connection point that joins a sandbox to a network. Each endpoint is a veth pair — one end in the container's namespace, the other end attached to the network (bridge, overlay, etc.). A container can have multiple endpoints on different networks.
Network: A group of endpoints that can communicate with each other. Implemented by a driver (bridge, overlay, macvlan). The driver determines how packets are forwarded between endpoints.
The Docker daemon manages all three objects. When you run docker network create, you create a network object. When you run docker run --network mynet, Docker creates a sandbox, an endpoint, and joins the endpoint to the network.
Why this matters: The CNM abstraction allows pluggable drivers. The same container can be on a bridge network (local communication) and an overlay network (multi-host communication) simultaneously. The sandbox isolates the container's view — it sees only the endpoints that are connected to it.
- Different workloads need different networking: single-host (bridge), multi-host (overlay), bare-metal performance (macvlan).
- A pluggable architecture lets third-party drivers (Calico, Cilium, Weave) integrate without modifying Docker.
- The CNM abstraction separates the 'what' (connect containers) from the 'how' (bridge, overlay, macvlan).
- The same container can be on multiple networks with different drivers simultaneously.
Bridge Networking Internals — The Linux Kernel View
Bridge networking is the default and most common Docker network driver. Understanding what happens at the kernel level when two containers on the same bridge network communicate is essential for debugging.
Step 1: Network namespace creation. When a container starts, Docker creates a new Linux network namespace. This namespace has its own interfaces, routing table, and iptables rules — completely isolated from the host and other containers.
Step 2: veth pair creation. Docker creates a virtual Ethernet (veth) pair. One end (vethXXXX) stays in the host's namespace. The other end (eth0) is moved into the container's namespace. They are connected like a virtual cable — packets sent into one end appear on the other.
Step 3: Bridge attachment. The host end of the veth pair is attached to a Linux bridge (br-XXXX). The bridge acts as a virtual switch — it forwards frames between all attached veth interfaces based on MAC address learning.
Step 4: IP address assignment. Docker's IPAM (IP Address Management) assigns an IP address from the bridge's subnet to the container's eth0 interface. The bridge itself gets the gateway IP (e.g., 172.18.0.1).
Step 5: iptables rules. Docker adds iptables rules to handle NAT for published ports, inter-network isolation (DOCKER-ISOLATION chains), and masquerading for outbound traffic.
Packet flow for container-to-container communication: Container A (172.18.0.2) sends a packet to Container B (172.18.0.3). The packet exits Container A's eth0, travels through the veth pair to the bridge. The bridge learns Container A's MAC address, looks up Container B's MAC in its forwarding table, and forwards the frame to Container B's veth host end. The packet travels through the veth pair into Container B's namespace and arrives at Container B's eth0. No iptables NAT is involved — this is direct L2 switching.
Packet flow for port publishing (external access): An external client sends a packet to the host's port 8000. iptables NAT rules (DOCKER chain) rewrite the destination from the host IP to the container's IP (DNAT). The packet enters the bridge and is forwarded to the container. The container processes the request and sends a reply. iptables rewrites the source from the container's IP to the host's IP (SNAT/masquerade). The reply reaches the external client.
- Every packet must traverse the veth pair — a virtual cable with kernel-level copying overhead.
- Published ports require iptables NAT (DNAT + SNAT) — each NAT rule adds processing time.
- The bridge performs MAC address lookup and forwarding — similar to a physical switch but in software.
- Combined overhead: ~10-50 microseconds per packet. For most workloads, this is negligible. For latency-critical workloads (trading, gaming), it matters.
Docker DNS Resolution — How Service Names Become IP Addresses
Docker's embedded DNS server is the mechanism that allows containers to reach each other by service name instead of IP address. Understanding how it works — and its limitations — prevents hours of debugging.
How it works: When you create a custom bridge network, Docker runs a DNS server at 127.0.0.11 inside each container on that network. The container's /etc/resolv.conf points to this DNS server. When a container resolves a service name, the request goes to 127.0.0.11, which maps the name to the container's internal IP on that network.
What gets resolved: - Container name: the name you gave the container with --name - Service name (Compose): the service name in docker-compose.yml - Container ID: the full or truncated container ID - Network alias: an additional name set with docker network connect --alias
What does NOT get resolved: - Containers on the default bridge network (no embedded DNS) - Containers on different networks (DNS is network-scoped) - Host names outside the Docker network (use the host's DNS)
The default bridge limitation: The default bridge network does NOT use Docker's embedded DNS. It uses the legacy /etc/hosts file approach, which only supports --link (deprecated). This is why containers on the default bridge cannot resolve each other by name without --link. Custom bridge networks use the embedded DNS server and support name resolution natively.
Round-robin DNS for load balancing: If multiple containers have the same network alias, Docker's DNS returns all IPs in round-robin order. This provides basic client-side load balancing without a dedicated load balancer.
- The default bridge predates the embedded DNS server — it was designed before user-defined networks existed.
- The default bridge uses the legacy /etc/hosts approach, which requires --link to add entries.
- --link is deprecated because it creates a hard coupling between containers and does not scale.
- Custom bridge networks use the embedded DNS server (127.0.0.11) which supports dynamic name resolution.
- Moral: never use the default bridge in production. Always create custom networks.
Overlay Networks — Multi-Host Container Communication
Overlay networks extend Docker networking across multiple hosts using VXLAN tunnels. This is the networking foundation for Docker Swarm and is also used by Kubernetes (via CNI plugins like Flannel and Calico).
How VXLAN works: VXLAN (Virtual Extensible LAN) encapsulates Layer 2 Ethernet frames inside Layer 3 UDP packets. Each overlay network gets a VNI (VXLAN Network Identifier) — like a VLAN ID but with a 24-bit address space (16 million networks vs 4096 VLANs). The encapsulation adds 50 bytes of overhead per packet (outer Ethernet + outer IP + outer UDP + VXLAN header).
Packet flow across hosts: Container A on Host 1 sends a packet to Container B on Host 2. The packet exits Container A's veth pair, reaches the overlay bridge on Host 1. The overlay driver encapsulates the packet in a VXLAN frame with the network's VNI. The encapsulated packet is sent via UDP (port 4789) to Host 2's physical IP. Host 2 decapsulates the packet, strips the VXLAN header, and forwards the inner frame to Container B's veth pair.
Performance impact: VXLAN encapsulation adds ~100-200 microseconds of latency per packet compared to bridge networking. The 50-byte overhead reduces effective MTU (typically 1450 bytes instead of 1500). For high-throughput workloads, this overhead is measurable — overlay networks typically achieve 85-90% of bare-metal throughput.
When to use overlay: Multi-host container communication in Docker Swarm or when you need a flat network across hosts without complex routing. Overlay is the right choice when simplicity matters more than raw performance.
When to avoid overlay: Latency-critical workloads (real-time trading, gaming), high-throughput data pipelines, or environments where the underlay network already provides L3 connectivity (use macvlan or direct routing instead).
- Bridge networking: packet goes from container -> veth -> bridge -> veth -> container. All on the same host.
- Overlay networking: packet goes from container -> veth -> overlay bridge -> VXLAN encapsulation -> physical NIC -> network -> physical NIC -> VXLAN decapsulation -> overlay bridge -> veth -> container.
- The VXLAN encapsulation/decapsulation adds ~100-200 microseconds.
- The 50-byte overhead reduces effective MTU, causing more packets for large transfers.
- Encryption (if enabled) adds additional overhead.
macvlan and host Networking — When Bridge Is Not Enough
Bridge networking is the right default for most workloads. But two scenarios require different drivers: when a container needs to appear as a physical device on the LAN (macvlan), and when latency must be minimized (host).
macvlan: Assigns a MAC address to the container, making it appear as a separate physical device on the network. The container gets an IP from the physical network's DHCP or static range. Other devices on the LAN can reach the container directly without NAT.
Use cases: legacy applications that require a unique MAC address, network appliances (firewalls, load balancers) that need to be on the physical network, IoT devices that communicate via broadcast.
Limitations: macvlan requires the host NIC to be in promiscuous mode (not allowed on some cloud providers). Containers on different macvlan subnets on the same host cannot communicate with each other (they go out to the physical switch and back, but the switch may not route between them). Requires careful VLAN configuration on the physical network.
host: Removes the network namespace entirely. The container uses the host's network stack directly. No veth pair, no bridge, no iptables NAT. The container can bind to any host port.
Use cases: latency-critical workloads (trading, gaming), network monitoring tools that need raw socket access, containers that need to bind to privileged ports (<1024).
Limitations: no port isolation — two containers cannot bind to the same port. no network isolation — the container can see all host network interfaces and traffic. Security risk — a compromised container has full network access to the host.
- macvlan creates a new MAC address for the container on the physical interface.
- When the host tries to reach the container, the packet goes out through the physical NIC to the switch.
- The switch sees the source and destination are on the same port and does not route the packet back.
- The fix is a macvlan shim interface on the host that acts as a bridge for host-to-container traffic.
iptables and Docker — The Firewall Rules You Never See
Docker manages iptables rules automatically to handle port publishing, inter-network isolation, and outbound masquerading. Understanding these rules is essential for debugging networking issues on hosts with complex firewall configurations.
Key iptables chains Docker creates: - DOCKER chain (nat table): DNAT rules for published ports. Maps host port to container IP:port. - DOCKER chain (filter table): Allows traffic to published ports. - DOCKER-ISOLATION-STAGE-1 and STAGE-2: Prevents traffic between different Docker networks. - DOCKER-USER chain: User-defined rules that are evaluated before Docker's rules. This is where you add custom firewall rules.
The conflict with ufw/firewalld: Docker bypasses ufw (Ubuntu) and firewalld (RHEL) by inserting rules directly into the iptables FORWARD chain. This means ufw may show port 8000 as blocked, but Docker's iptables rules allow it anyway. This is a common source of confusion and security gaps.
The DOCKER-USER chain: Docker never modifies this chain. It is the safe place to add custom firewall rules that apply to Docker traffic. Rules in DOCKER-USER are evaluated before Docker's own rules. Use this to restrict which external IPs can access published ports.
Performance impact: Each published port creates at least one DNAT rule and one filter rule. With 100 published ports, the iptables rule chain is evaluated for every packet. On high-throughput hosts, this adds measurable latency. Minimize published ports — use a reverse proxy (nginx, Traefik) that publishes a single port and routes internally.
- Docker inserts iptables rules directly into the FORWARD and nat PREROUTING chains.
- ufw and firewalld manage rules in the INPUT chain, not FORWARD.
- Traffic to published ports goes through FORWARD (not INPUT), so ufw rules do not apply.
- This creates a security gap: ufw shows the port as blocked, but Docker's rules allow it.
- The fix: use the DOCKER-USER chain for custom rules, or set iptables=false in daemon.json and manage rules manually.
Intermittent Connection Refused Between Containers on Default Bridge Network
- The default bridge network does not support DNS resolution by container name. Only custom bridge networks do.
- --link is deprecated and should never be used. Custom networks with embedded DNS replace it entirely.
- Intermittent DNS failures in Docker are almost always caused by mixing default bridge and custom network configurations.
- Always use custom bridge networks in production — the default bridge is a legacy artifact.
- Validate network configuration in CI to catch these issues before deployment.
Key takeaways
Interview Questions on This Topic
Frequently Asked Questions
That's Docker. Mark it forged?
8 min read · try the examples if you haven't