MinhVo

Minh Vo

rss feed

Slaying code & making it lit fr fr 🔥 tagline

Hey there 👋 I'm an AI Engineer with 7 years of experience building scalable web and mobile applications. Currently at Neurond AI (May 2025 — present), architecting an Enterprise AI Assistant Platform with multi-tenant RAG on pgvector, multi-provider LLM orchestration, and Azure-native infrastructure. Previously spent 5+ years at SNAPTEC (Sep 2019 — Apr 2025), leading SaaS themes, admin dashboards, and e-commerce platforms — earned the Hero of the Year award in 2021. I specialize in TypeScript, React, Next.js, and AI-Native engineering with Claude Code and Cursor.bio

Back to blogs

Docker Networking: Bridge, Host, and Overlay

Understand Docker networking: bridge networks, host mode, overlay, and DNS resolution.

DockerNetworkingContainersDevOps

By MinhVo

Introduction

Networking is the invisible infrastructure that connects containers to each other, to the host system, and to the outside world. Without a solid understanding of Docker networking, developers encounter mysterious connection failures, intermittent DNS resolution issues, and performance problems that are difficult to diagnose. These issues often surface only in production-like multi-container environments, making them particularly frustrating to debug.

Docker provides several networking drivers, each designed for specific use cases. The default bridge network handles single-host container communication. The host network eliminates network overhead for performance-critical applications. Overlay networks enable communication across multiple Docker hosts in a swarm. Understanding when to use each driver and how they differ at the packet level is essential for building reliable containerized applications.

This guide covers the internals of Docker networking, from the Linux kernel features that make it possible to the practical patterns for configuring networks in production environments. You will learn how packets flow between containers, how DNS resolution works in user-defined networks, and how to troubleshoot common networking issues.

Network infrastructure concept

Understanding Docker Networking: Core Concepts

Docker networking is built on Linux kernel networking features: network namespaces, virtual Ethernet pairs (veth pairs), bridges, and iptables rules. Each container gets its own network namespace, which provides an isolated network stack with its own interfaces, routes, and firewall rules.

Network Namespaces

When Docker creates a container, it creates a new network namespace for that container. This namespace contains a complete, independent network stack: its own interfaces, routing table, and firewall rules. The container's eth0 interface is actually one end of a veth pair, with the other end connected to a bridge on the host.

# List network namespaces on the host (requires root)
sudo ls /var/run/netns/
 
# Inspect a container's network namespace
docker inspect --format '{{.NetworkSettings.SandboxKey}}' my-container
 
# Use nsenter to access a container's network namespace from the host
PID=$(docker inspect --format '{{.State.Pid}}' my-container)
sudo nsenter -t $PID -n ip addr show

The Docker Network Subsystem

Docker manages several network objects:

  • Networks: Virtual switches that connect containers. Each network has its own subnet and gateway.
  • Endpoints: A container's connection to a network. A container can have endpoints on multiple networks.
  • Services: DNS entries that resolve to container IPs within a network. Docker Compose creates services automatically.
# List all Docker networks
docker network ls
 
# Inspect network details
docker network inspect bridge
 
# Create a custom network
docker network create my-network
 
# Connect a running container to a network
docker network connect my-network my-container
 
# Disconnect a container from a network
docker network disconnect my-network my-container

Architecture and Design Patterns

Bridge Network Architecture

The default bridge network (docker0) is created automatically when Docker starts. It assigns containers IP addresses from a private subnet (typically 172.17.0.0/16) and uses NAT to provide outbound internet access. Containers on the default bridge can communicate with each other by IP address but not by name.

User-defined bridge networks improve on the default in critical ways. They provide automatic DNS resolution between containers by service name, better network isolation, and the ability to connect and disconnect containers at runtime without restarting them.

# Default bridge: containers communicate by IP only
docker run -d --name web nginx:alpine
docker run --rm alpine ping -c 1 172.17.0.2  # Works
docker run --rm alpine ping -c 1 web          # Fails (no DNS)
 
# User-defined bridge: containers communicate by name
docker network create my-app
docker run -d --name web --network my-app nginx:alpine
docker run --rm --network my-app alpine ping -c 1 web  # Works

Host Network Architecture

The host network driver removes network isolation between the container and the host. The container shares the host's network namespace directly, meaning it uses the host's IP address and ports. This eliminates the overhead of NAT and bridge routing but sacrifices network isolation.

# Host network mode: container uses host's network stack
docker run -d --network host nginx:alpine
# Nginx is now directly on the host's port 80
curl http://localhost:80

Host networking is valuable for performance-critical applications that handle high throughput or require low latency. It is also useful for containers that need to bind to many ports or interact with host-level network services.

Overlay Network Architecture

Overlay networks enable communication between containers running on different Docker hosts. They use VXLAN encapsulation to tunnel Layer 2 traffic over the existing Layer 3 infrastructure between hosts. Docker Swarm uses overlay networks as its primary networking mechanism.

# Initialize Docker Swarm (required for overlay networks)
docker swarm init
 
# Create an overlay network
docker network create -d overlay my-overlay
 
# Deploy services on the overlay
docker service create --name web --network my-overlay --replicas 3 nginx:alpine
docker service create --name api --network my-overlay node:20-alpine

Network Drivers Comparison

Each Docker network driver is designed for specific use cases. Choosing the right driver depends on your isolation requirements, performance needs, and deployment topology.

# Create networks with different drivers
docker network create --driver bridge my-bridge      # Single host
docker network create --driver overlay my-overlay    # Multi-host
docker network create --driver macvlan \
  --subnet 192.168.1.0/24 \
  --gateway 192.168.1.1 \
  -o parent=eth0 my-macvlan                          # Direct LAN access

Step-by-Step Implementation

Setting Up a Multi-Service Application Network

A typical web application has multiple services that need to communicate: a web server, an API, a database, and a cache. Proper network configuration ensures these services can find each other while remaining isolated from the internet.

# docker-compose.yml - Networked multi-service application
version: '3.8'
 
services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    networks:
      - frontend
    depends_on:
      - api
 
  api:
    build: ./api
    expose:
      - "3000"
    networks:
      - frontend
      - backend
    environment:
      - DATABASE_URL=postgres://app:secret@db:5432/myapp
      - REDIS_URL=redis://cache:6379
 
  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - backend
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=app
      - POSTGRES_PASSWORD=secret
 
  cache:
    image: redis:7-alpine
    networks:
      - backend
 
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No internet access for backend services
 
volumes:
  pgdata:

The internal: true flag on the backend network is a critical security feature. It prevents containers on that network from accessing the internet, which means the database and cache cannot make outbound connections. This limits the impact of a compromised application container.

Configuring Network Isolation Between Services

Network segmentation ensures that services can only reach the other services they need. The API needs access to the database and cache, but the frontend should only reach the API.

version: '3.8'
 
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    networks:
      - public
 
  api:
    build: ./api
    networks:
      - public
      - api-db
 
  worker:
    build: ./worker
    networks:
      - api-db
      - cache-net
 
  db:
    image: postgres:16-alpine
    networks:
      - api-db
 
  cache:
    image: redis:7-alpine
    networks:
      - cache-net
 
networks:
  public:
  api-db:
    internal: true
  cache-net:
    internal: true

Custom Subnet Configuration

For environments where the default Docker subnet conflicts with existing infrastructure, you can specify custom subnets.

# Create a network with a specific subnet
docker network create \
  --driver bridge \
  --subnet 10.10.0.0/24 \
  --gateway 10.10.0.1 \
  --ip-range 10.10.0.128/25 \
  my-custom-network
 
# Assign a static IP to a container
docker run -d \
  --network my-custom-network \
  --ip 10.10.0.10 \
  --name db \
  postgres:16-alpine
# docker-compose.yml with custom IP configuration
version: '3.8'
 
services:
  db:
    image: postgres:16-alpine
    networks:
      backend:
        ipv4_address: 10.10.0.10
 
  api:
    build: ./api
    networks:
      backend:
        ipv4_address: 10.10.0.20
 
networks:
  backend:
    ipam:
      config:
        - subnet: 10.10.0.0/24
          gateway: 10.10.0.1

DNS Resolution in Docker Networks

Docker provides built-in DNS resolution for containers on user-defined networks. Each container can reach other containers by their service name or container name. This DNS server runs at 127.0.0.11 inside each container.

# Verify DNS resolution inside a container
docker exec my-api nslookup db
# Server:    127.0.0.11
# Address:   127.0.0.11#53
# Name:      db.my-network
# Address:   10.10.0.10
 
# Check the DNS configuration
docker exec my-api cat /etc/resolv.conf
# nameserver 127.0.0.11
# options ndots:0

Docker's DNS resolution supports aliasing, allowing a single container to be reached by multiple names:

version: '3.8'
 
services:
  database:
    image: postgres:16-alpine
    networks:
      backend:
        aliases:
          - db
          - postgres
          - primary-db
 
  api:
    build: ./api
    networks:
      - backend
    environment:
      # All three resolve to the same container
      - DATABASE_URL=postgres://app:secret@primary-db:5432/myapp
 
networks:
  backend:

Real-World Use Cases and Case Studies

Use Case 1: Microservices Network Segmentation

A fintech platform with 15 microservices implemented network segmentation to meet PCI-DSS requirements. Payment processing services were placed on an isolated internal network, while user-facing services connected to both the public and internal networks. This architecture ensured that even if a public-facing container was compromised, the attacker could not directly reach the payment processing services without pivoting through the API gateway.

Use Case 2: High-Throughput Data Pipeline

A data analytics company processing 100,000 events per second switched their Kafka consumers from bridge networking to host networking. The elimination of NAT overhead and bridge routing reduced network latency by 40% and increased throughput by 25%. The trade-off of reduced network isolation was acceptable because the Kafka consumers ran on dedicated hosts with no other workloads.

Use Case 3: Multi-Host Service Mesh

A SaaS platform with services spread across 8 Docker hosts used overlay networks to create a unified communication fabric. Services could discover and communicate with each other regardless of which host they were running on, using Docker's built-in DNS resolution. This simplified their deployment model and eliminated the need for external service discovery infrastructure.

Use Case 4: Development Environment Isolation

A consulting firm running multiple client projects on a shared Docker host used custom bridge networks to isolate each project's containers. Each project received its own network with a unique subnet, preventing accidental cross-project communication. Developers could run identical service names (like db or redis) for different projects without conflicts.

Best Practices for Production

  1. Always use user-defined bridge networks: The default bridge network lacks DNS resolution and has weaker isolation. Create explicit networks for every application and avoid using the default bridge entirely.

  2. Apply the principle of least privilege: Place services on the minimum number of networks they need. A database should only be on the backend network, not the frontend network. Use the internal: true flag for networks that should not have internet access.

  3. Use host networking judiciously: Reserve host networking for performance-critical workloads where the overhead of bridge networking is measurable and significant. For most applications, bridge networking provides sufficient performance with better isolation.

  4. Configure health checks for network dependencies: Services should verify their network dependencies are available before accepting traffic. Use Docker Compose depends_on with condition: service_healthy to control startup order.

  5. Avoid hardcoded IP addresses: Use DNS names (service names in Compose) for inter-container communication. Hardcoded IPs break when containers are recreated with different addresses. Static IPs should only be used when external systems require them.

  6. Monitor network traffic: Use tools like tcpdump and Prometheus with the cadvisor exporter to monitor container network traffic. This helps identify bottlenecks, misconfigurations, and unexpected communication patterns.

  7. Document your network topology: Maintain documentation of which services communicate with which, on which networks, and on which ports. This is critical for troubleshooting and security auditing.

  8. Use encrypted overlay networks for sensitive data: When using overlay networks across hosts, enable encryption to protect data in transit between containers on different hosts.

Common Pitfalls and Solutions

PitfallImpactSolution
Using default bridge networkNo DNS resolution between containers; weak isolationCreate user-defined networks: docker network create my-app
Containers on different networks cannot communicateService discovery failuresConnect containers to shared networks or use the API gateway pattern
Port conflicts with host networkingContainer fails to start because port is already in useUse bridge networking with port mapping, or ensure port availability before starting containers
DNS caching causing stale connectionsContainers connect to old IP after a service restartsReduce DNS TTL in applications; use Docker's embedded DNS which handles this automatically
Overlay network performance overheadIncreased latency for cross-host communicationUse host networking for latency-sensitive services; optimize MTU settings for overlay networks
Firewall blocking Docker networkingContainers cannot reach each other or the internetConfigure firewall rules to allow Docker bridge traffic; check iptables rules
Internal network blocking needed outbound trafficServices cannot reach external APIsDo not use internal: true if services need outbound access; use specific network policies instead
Container hostname resolution fails across Compose filesServices defined in separate compose files cannot discover each otherUse external: true networks to share networks across compose files

Performance Optimization

Network Mode Performance Comparison

// Network benchmark results (approximate)
const benchmarkResults = {
  bridge: {
    latencyMs: 0.15,
    throughputGbps: 9.5,
    overhead: 'NAT + bridge routing',
    isolation: 'Full'
  },
  host: {
    latencyMs: 0.05,
    throughputGbps: 10,
    overhead: 'None',
    isolation: 'None'
  },
  overlay: {
    latencyMs: 0.4,
    throughputGbps: 3,
    overhead: 'VXLAN encapsulation + encryption',
    isolation: 'Full (cross-host)'
  },
  macvlan: {
    latencyMs: 0.08,
    throughputGbps: 9.8,
    overhead: 'Minimal (direct L2)',
    isolation: 'VLAN-level'
  }
};

Optimizing DNS Resolution

Docker's embedded DNS server at 127.0.0.11 handles name resolution for user-defined networks. For applications making frequent DNS queries, consider these optimizations:

services:
  api:
    build: ./api
    dns:
      - 127.0.0.11      # Docker's embedded DNS
      - 8.8.8.8          # Fallback to Google DNS
    dns_opts:
      - "ndots:0"         # Reduce unnecessary DNS lookups
      - "timeout:1"       # Fast timeout for failed lookups
      - "attempts:2"      # Limit retry attempts
    networks:
      - backend

MTU Configuration for Overlay Networks

Overlay networks add VXLAN headers (50 bytes) to each packet. If the underlying network does not support jumbo frames, this can cause fragmentation and performance degradation.

# Create overlay network with custom MTU
docker network create -d overlay \
  --opt com.docker.network.driver.mtu=1400 \
  my-overlay

Comparison with Alternatives

FeatureDocker BridgeDocker HostDocker OverlayKubernetes CNIIstio Service Mesh
Multi-host supportNoNoYesYesYes
DNS resolutionBuilt-inHost DNSBuilt-inCoreDNSBuilt-in
Network policiesLimitedNoneLimitedFull (Calico/Cilium)Full (Envoy)
EncryptionNoNoOptionalCNI-dependentmTLS default
Performance overheadLowNoneModerateLow to moderateModerate
ComplexityLowVery lowModerateHighVery high
Best forSingle-host appsPerformance-criticalDocker SwarmProduction K8sEnterprise microservices

Advanced Patterns and Techniques

Cross-Network Communication Gateway

When services on different networks need to communicate, use a gateway container connected to both networks.

version: '3.8'
 
services:
  gateway:
    image: nginx:alpine
    networks:
      - frontend
      - backend
    volumes:
      - ./nginx-gateway.conf:/etc/nginx/nginx.conf:ro
 
  web-app:
    build: ./frontend
    networks:
      - frontend
 
  api:
    build: ./backend
    networks:
      - backend
 
networks:
  frontend:
  backend:
    internal: true

Network Traffic Monitoring with Prometheus

version: '3.8'
 
services:
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "8080:8080"
    networks:
      - monitoring
 
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      - monitoring
 
networks:
  monitoring:
    internal: true

Testing Strategies

# Test network connectivity between services
test_network_connectivity() {
  local network=$1
  local from=$2
  local to=$3
  local port=$4
 
  docker run --rm --network "$network" alpine \
    sh -c "nc -zv $to $port" 2>&1 | grep -q "open"
  
  if [ $? -eq 0 ]; then
    echo "PASS: $from can reach $to:$port on $network"
  else
    echo "FAIL: $from cannot reach $to:$port on $network"
  fi
}
 
# Test DNS resolution
test_dns_resolution() {
  local network=$1
  local hostname=$2
 
  result=$(docker run --rm --network "$network" alpine \
    nslookup "$hostname" 2>&1)
  
  echo "$result" | grep -q "Address" && \
    echo "PASS: $hostname resolves on $network" || \
    echo "FAIL: $hostname does not resolve on $network"
}
 
# Test network isolation
test_network_isolation() {
  local from_network=$1
  local target=$2
  local port=$3
 
  docker run --rm --network "$from_network" alpine \
    sh -c "nc -zv -w 2 $target $port" 2>&1 | grep -q "open"
  
  if [ $? -ne 0 ]; then
    echo "PASS: $target:$port not reachable from $from_network (isolated)"
  else
    echo "FAIL: $target:$port reachable from $from_network (not isolated)"
  fi
}
 
test_network_connectivity "my-app" "api" "db" "5432"
test_dns_resolution "my-app" "api"
test_network_isolation "frontend" "db" "5432"

Future Outlook

Docker networking continues to evolve with better integration with CNI (Container Network Interface) plugins, improved performance for overlay networks, and enhanced security through network policies. eBPF-based networking, pioneered by Cilium in the Kubernetes ecosystem, may eventually influence Docker's networking stack, providing more efficient packet processing and deeper observability.

The convergence of Docker networking with service mesh technologies like Istio and Linkerd is also notable. While Docker provides basic connectivity, service meshes add mTLS, traffic management, and observability on top. Understanding Docker networking fundamentals is essential for effectively using these higher-level abstractions.

Conclusion

Docker networking is built on Linux kernel primitives that provide strong isolation, flexible connectivity, and automatic service discovery. The three primary network drivers serve distinct purposes:

  1. Bridge networks are the default for single-host container communication. Always use user-defined bridge networks rather than the default bridge to get DNS resolution and better isolation.
  2. Host networking eliminates network overhead for performance-critical workloads but sacrifices network isolation. Use it when bridge networking overhead is measurable and significant.
  3. Overlay networks enable multi-host communication for Docker Swarm deployments. They add VXLAN encapsulation overhead but provide seamless cross-host connectivity.

Key practices for production Docker networking:

  • Segment networks by function and security boundary
  • Use internal: true for networks that should not access the internet
  • Rely on DNS names rather than IP addresses for service discovery
  • Monitor network traffic and set up alerts for unexpected communication patterns
  • Document your network topology alongside your application architecture

With these foundations, you can build reliable, secure, and performant network configurations for any containerized application, from a simple two-service setup to a complex multi-host microservices architecture.