Docker Networking Deep Dive
Docker provides a software-defined networking subsystem that isolates container network interfaces while enabling seamless inter-service discovery. In this chapter, explore the Linux virtual ethernet plumbing, the 127.0.0.11 embedded DNS resolver, driver selection tradeoffs, and multi-tier network isolation.
1. The Under-the-Hood Plumbing: veth Pairs & iptables
When a container launches on a bridge network, the Docker daemon performs three Linux kernel configurations:
- Creates a Virtual Ethernet Pair (
veth): A virtual wire consisting of two peer endpoints. One endpoint is plugged into the software bridge on the host (e.g.docker0orbr-<id>), and the other endpoint is assigned inside the container's privateNETnamespace aseth0. - Allocates a Subnet IP Address: Assigns an IP (e.g.
172.18.0.2/16) to the container and configures a default gateway routing table. - Programs iptables / nftables NAT Rules: Sets up Network Address Translation (NAT) so outgoing packets from the container masquerade as the host machine's physical IP, and published inbound ports forward traffic directly to the container.
2. Network Drivers Comparison Matrix
| Driver | Isolation & Routing Mechanics | Production Verdict & Use Case |
|---|---|---|
| bridge (Default) | Software virtual bridge switch on a single host. Containers receive private IPs on an isolated subnet. | The Industry Standard. Use for 95% of standalone applications and multi-container Compose stacks. |
| host | Disables network namespace isolation. The container shares the host's network stack directly (no port mapping needed). | High-throughput ultra-low latency workloads (e.g. live streaming, VoIP, load testing). Risk: port collisions. |
| overlay | Creates a distributed multi-host VXLAN tunnel network across multiple Docker daemons. | Swarm clusters and enterprise multi-node architectures. |
| macvlan | Assigns a real physical MAC address from your local physical LAN router to each container. | Legacy applications that require direct Layer 2 LAN presence with dedicated router IP assignments. |
| none | Only the loopback (127.0.0.1) interface exists. No internet or inter-container connectivity. | High-security air-gapped workloads (batch crypto processing, sandboxed code execution). |
3. User-Defined Bridge vs Default Bridge (The DNS Trap)
The Default Bridge Gotcha
When you launch containers without specifying a network (docker run nginx), they attach to the legacy default bridge (docker0). The default bridge DOES NOT provide automatic DNS resolution by name!If container A attempts to query http://container-b:3000, the lookup fails unless you hardcode raw IP addresses.
Always create a User-Defined Bridge Network. User-defined networks activate Docker's embedded DNS server listening at 127.0.0.11, allowing services to find each other by name:
# 1. Create a dedicated bridge network
docker network create --driver bridge app-tier
# 2. Start PostgreSQL with container name 'database'
docker run -d \
--name database \
--network app-tier \
-e POSTGRES_PASSWORD=secret \
postgres:16-alpine
# 3. Start API server on the same network
# The API connects to PostgreSQL using hostname 'database:5432'
docker run -d \
--name api-service \
--network app-tier \
-e DB_URL="postgresql://postgres:secret@database:5432/app" \
-p 8080:8080 \
my-api:latest
# 4. Verify automatic DNS resolution inside the running API container:
docker exec api-service ping -c 2 database4. Production Architecture: Multi-Tier Network Isolation
In production, never put your database on the same network as public-facing reverse proxies. Implement Defense-in-Depth by attaching containers to multiple distinct networks:
Nginx Proxy
frontend-net onlyBackend API
frontend-netbackend-netPostgreSQL DB
backend-net only# 1. Create isolated network tiers
docker network create frontend-net
docker network create backend-net
# 2. Run Database strictly on backend-net (invisible from frontend)
docker run -d --name db --network backend-net postgres:16-alpine
# 3. Run API on frontend-net, then connect it to backend-net as well
docker run -d --name api --network frontend-net my-api:latest
docker network connect backend-net api
# 4. Run Nginx strictly on frontend-net
docker run -d --name proxy --network frontend-net -p 80:80 nginx:alpine
# Security Result: Even if the Nginx proxy is compromised, it cannot directly reach or ping the database!Next Up: Docker Compose Basics
In Chapter 11, learn how to declare multi-container stacks, networks, and persistent volumes in a single compose.yaml file.
Chapter 11: Docker Compose Basics →