Docker Networking 2025 — Bridge, Host, Overlay, and Macvlan Explained
Advertisement
Introduction
Why This Matters
Networking is the invisible layer that makes or breaks containerized applications. Developers who do not understand Docker networking spend hours debugging "connection refused" errors, wondering why container A cannot reach container B even though both are "running." Production incidents often trace back to misconfigured network policies, unexpected port exposure, or cross-host routing failures.
Understanding Docker network drivers is also the foundation for Kubernetes networking. Pod-to-pod communication, service discovery via CoreDNS, and NetworkPolicy all build on the same concepts. Engineers who understand bridge networking, DNS resolution, and overlay networks transition to Kubernetes networking much faster than those who treat networking as a black box.
Docker Network Drivers Overview
Docker ships with five built-in network drivers:
| Driver | Use Case |
|---|---|
| bridge | Default for single-host container communication |
| host | Share host network stack (no isolation) |
| overlay | Multi-host communication in Docker Swarm |
| macvlan | Containers need a MAC address on the physical network |
| none | Complete network isolation |
# List all networks
docker network ls
# NETWORK ID NAME DRIVER SCOPE
# abc123 bridge bridge local
# def456 host host local
# ghi789 none null localBridge Networking (Default)
The bridge driver creates a private internal network on the Docker host. Containers on the same bridge can communicate; external access requires port mapping.
# Default bridge: containers communicate by IP only (not hostname)
docker run -d --name web nginx
docker run -d --name api myapp
# Containers on the default bridge cannot resolve each other by name
# Must use IP: docker inspect web | grep IPAddress
# User-defined bridge: containers resolve each other by container name
docker network create app-network
docker run -d --network app-network --name web nginx
docker run -d --network app-network --name api myapp
# Now 'api' can reach 'web' by hostname 'web'
docker exec api curl http://web:80Key difference: The default bridge network does not support DNS resolution by container name. User-defined bridge networks do. Always create user-defined networks for production containers.
# Create a bridge network with custom subnet
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
--ip-range 172.20.240.0/20 \
app-network
# Assign a static IP to a container
docker run -d \
--network app-network \
--ip 172.20.240.10 \
--name db postgres:16Port Mapping and Exposure
# Map container port 3000 to host port 8080
docker run -d -p 8080:3000 myapp
# Map to all interfaces (default)
docker run -d -p 0.0.0.0:8080:3000 myapp
# Map to a specific interface only (more secure)
docker run -d -p 127.0.0.1:8080:3000 myapp
# Map multiple ports
docker run -d -p 80:80 -p 443:443 nginx
# Map to a random host port
docker run -d -p 3000 myapp
docker port myapp # shows which host port was assignedEXPOSE in a Dockerfile documents which ports the container uses but does NOT publish them. -p at runtime is required to make ports accessible from outside the container.
Host Networking
The host driver removes network isolation — the container shares the host's network stack directly:
docker run -d --network host nginx
# nginx now listens on the host's port 80 directly
# No port mapping needed (or possible)Use cases: performance-critical applications where the NAT overhead of bridge networking matters, or tools that need to monitor host network interfaces (packet sniffers, network scanners).
Do not use host networking for regular application containers in production — it bypasses container network isolation.
DNS Resolution in Docker
Docker's embedded DNS resolver (127.0.0.11) handles name resolution for user-defined networks:
# Check DNS inside a container
docker exec -it api cat /etc/resolv.conf
# nameserver 127.0.0.11
# options ndots:0
# Test resolution
docker exec api nslookup db
# Server: 127.0.0.11
# Name: db
# Address: 172.20.0.3In Docker Compose, all services are automatically on the same network and resolve by service name:
services:
api:
image: myapp
environment:
# 'db' resolves to the postgres container
- DATABASE_URL=postgres://user:pass@db:5432/mydb
db:
image: postgres:16Network Isolation Between Service Tiers
Separate frontend, application, and database tiers onto different networks:
version: '3.8'
services:
nginx:
image: nginx:alpine
networks:
- frontend
ports:
- "80:80"
api:
build: .
networks:
- frontend # reachable from nginx
- backend # can reach the database
# NOT exposed on host
db:
image: postgres:16-alpine
networks:
- backend # isolated from nginx
# No ports exposed to host
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # no external routing; purely internalThe internal: true flag prevents containers on backend from reaching the internet — database containers have no outbound internet access.
Connecting to External Networks
# Connect a running container to an additional network
docker network connect app-network container_name
# Disconnect a container from a network
docker network disconnect app-network container_name
# Inspect network details (shows all connected containers and IPs)
docker network inspect app-networkOverlay Networking for Multi-Host (Docker Swarm)
Overlay networks span multiple Docker hosts, enabling containers on different machines to communicate as if they were on the same local network:
# Initialize Docker Swarm
docker swarm init --advertise-addr 192.168.1.10
# Create an overlay network
docker network create \
--driver overlay \
--attachable \
prod-network
# Deploy a service on the overlay network
docker service create \
--name api \
--network prod-network \
--replicas 3 \
myapp:1.0Overlay networking uses VXLAN encapsulation to tunnel traffic between hosts. In Kubernetes, this concept maps to Container Network Interface (CNI) plugins like Flannel, Calico, and Cilium.
Macvlan Networking
Macvlan assigns a real MAC address to each container, making it appear as a physical device on the network:
docker network create \
--driver macvlan \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
--opt parent=eth0 \
macvlan-net
docker run -d \
--network macvlan-net \
--ip 192.168.1.50 \
--name legacy-app \
legacy-image:1.0Use macvlan when legacy applications require a specific IP on the physical network (hardware licensing, firewall rules).
Debugging Network Issues
# Check container IP and network config
docker inspect container_name | grep -A 20 '"Networks"'
# Test connectivity between containers
docker exec api ping -c 3 db
docker exec api curl -v http://db:5432
# Check which ports are exposed
docker port container_name
# Capture network traffic (requires --network host and tcpdump)
docker run --rm --network container:api \
-v $(pwd):/captures \
nicolaka/netshoot \
tcpdump -w /captures/traffic.pcap
# Use netshoot for comprehensive network debugging
docker run --rm -it --network container:api nicolaka/netshootCommon Mistakes
- Relying on the default
bridgenetwork for container-to-container communication — DNS resolution does not work on the default bridge - Binding ports to
0.0.0.0(all interfaces) when only localhost access is needed — exposes services to the network - Using
--network hostfor application containers in production — removes isolation and creates port conflict risks - Not using
internal: trueon database networks — databases can potentially make outbound connections - Hardcoding container IPs instead of using DNS hostnames — IPs change when containers restart
Best Practices
- Always create user-defined bridge networks; never rely on the default
bridgefor service-to-service communication - Bind sensitive ports to
127.0.0.1not0.0.0.0:-p 127.0.0.1:5432:5432for databases - Use network segmentation (frontend/backend networks) to enforce least-privilege connectivity between services
- Use
nicolaka/netshootcontainer for live network debugging — it has every tool (curl, dig, tcpdump, nmap) - Name your networks descriptively:
payment-backend,auth-frontend, notnet1,net2
Key Takeaways
- User-defined bridge networks support DNS resolution by container name; the default bridge network does not
- Port mapping (
-p hostPort:containerPort) publishes ports to the host; EXPOSE in Dockerfile is documentation only - Host networking removes network isolation and should only be used for monitoring or performance-critical tools
- Docker Compose creates a default network for all services automatically, enabling name-based service discovery
- The
internal: trueflag on a network blocks outbound internet access — ideal for database networks - Overlay networks enable multi-host container communication in Docker Swarm using VXLAN encapsulation
- Always use
nicolaka/netshootfor debugging — it provides traceroute, nmap, dig, and tcpdump in one image - Separate your services into frontend and backend networks to enforce security boundaries at the network layer
Advertisement