Container Networking

Container Networking

Learning Objectives

  • Understand Docker network drivers and their use cases
  • Master bridge, host, overlay, and macvlan networks
  • Configure custom networks with subnets, gateways, and DNS
  • Implement service discovery and inter-container communication
  • Troubleshoot network connectivity issues
  • Apply network security best practices

Table of Contents

  1. Docker Network Drivers
  2. Bridge Network Deep Dive
  3. Host and None Networks
  4. Overlay Networks
  5. Network Configuration
  6. DNS and Service Discovery
  7. Port Mapping Advanced
  8. Network Security
  9. Troubleshooting
  10. Practice Exercises

Difficulty: ⭐⭐⭐


1. Docker Network Drivers

Docker provides multiple network drivers for different use cases.

Network Driver Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Docker Network Drivers                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  bridge  β”‚  β”‚   host   β”‚  β”‚ overlay  β”‚  β”‚ macvlan  β”‚   β”‚
β”‚  β”‚          β”‚  β”‚          β”‚  β”‚          β”‚  β”‚          β”‚   β”‚
β”‚  β”‚ Default  β”‚  β”‚  Native  β”‚  β”‚  Swarm   β”‚  β”‚  Legacy  β”‚   β”‚
β”‚  β”‚ Isolated β”‚  β”‚  Network β”‚  β”‚Multi-hostβ”‚  β”‚  Bridge  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                              β”‚
β”‚              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                    β”‚
β”‚              β”‚   none   β”‚                                    β”‚
β”‚              β”‚          β”‚                                    β”‚
β”‚              β”‚ Disabled β”‚                                    β”‚
β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Listing Networks

# List all networks
docker network ls

# Output:
# NETWORK ID     NAME      DRIVER    SCOPE
# 3c7f2a8b4d91   bridge    bridge    local
# 9f8e3d2c1a45   host      host      local
# 1b5a6c9d3e72   none      null      local

Inspecting Networks

# Detailed network information
docker network inspect bridge

# Output (truncated):
# [
#     {
#         "Name": "bridge",
#         "Driver": "bridge",
#         "IPAM": {
#             "Config": [
#                 {
#                     "Subnet": "172.17.0.0/16",
#                     "Gateway": "172.17.0.1"
#                 }
#             ]
#         },
#         "Containers": {...}
#     }
# ]

Network Driver Use Cases

Driver Use Case Scope DNS
bridge Single-host, isolated containers Local Yes (user-defined)
host High performance, no isolation Local Host DNS
overlay Multi-host, Swarm services Swarm Yes
macvlan Legacy apps needing MAC addresses Local No
none Complete isolation, custom networking Local No

2. Bridge Network Deep Dive

Bridge networks are the most common network type for containers.

Default Bridge vs User-Defined Bridge

Default Bridge Network              User-Defined Bridge Network
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   172.17.0.0/16      β”‚            β”‚   172.20.0.0/16      β”‚
β”‚                      β”‚            β”‚                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚            β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚ Container1 β”‚      β”‚            β”‚  β”‚ Container1 β”‚      β”‚
β”‚  β”‚ 172.17.0.2 β”‚      β”‚            β”‚  β”‚ 172.20.0.2 β”‚      β”‚
β”‚  β”‚            β”‚      β”‚            β”‚  β”‚ web        β”‚      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚            β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                      β”‚            β”‚         β”‚            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚            β”‚         β”‚ DNS        β”‚
β”‚  β”‚ Container2 β”‚      β”‚            β”‚         β–Ό            β”‚
β”‚  β”‚ 172.17.0.3 β”‚      β”‚            β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚            β”‚      β”‚            β”‚  β”‚ Container2 β”‚      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚            β”‚  β”‚ 172.20.0.3 β”‚      β”‚
β”‚                      β”‚            β”‚  β”‚ db         β”‚      β”‚
β”‚  No automatic DNS    β”‚            β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚  Link by IP only     β”‚            β”‚                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β”‚  Automatic DNS       β”‚
                                    β”‚  Link by name        β”‚
                                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Creating a User-Defined Bridge Network

# Create custom bridge network
docker network create my-app-network

# Create with custom subnet
docker network create \
  --driver bridge \
  --subnet 172.25.0.0/16 \
  --gateway 172.25.0.1 \
  my-custom-network

# Create with IP range reservation
docker network create \
  --subnet 172.26.0.0/16 \
  --ip-range 172.26.5.0/24 \
  my-reserved-network

Connecting Containers to Bridge Networks

# Run container on custom network
docker run -d \
  --name web \
  --network my-app-network \
  nginx

# Run another container on same network
docker run -d \
  --name db \
  --network my-app-network \
  postgres

# Test DNS resolution
docker exec web ping db
# PING db (172.25.0.3): 56 data bytes
# 64 bytes from 172.25.0.3: seq=0 ttl=64 time=0.123 ms

Connecting/Disconnecting Networks at Runtime

# Connect running container to additional network
docker network connect my-app-network my-container

# Disconnect from network
docker network disconnect my-app-network my-container

# Connect with static IP
docker network connect --ip 172.25.0.100 my-app-network my-container

Docker Compose Bridge Network

# docker-compose.yml
version: '3.8'

services:
  web:
    image: nginx
    networks:
      - frontend
      - backend

  app:
    image: myapp:latest
    networks:
      backend:
        ipv4_address: 172.28.0.100

  db:
    image: postgres
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16
          gateway: 172.28.0.1

3. Host and None Networks

Host Network

Containers share the host's network stack directly.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Host Network                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚         Host OS Network           β”‚  β”‚
β”‚  β”‚                                   β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚  β”‚
β”‚  β”‚  β”‚Container1β”‚    β”‚Container2β”‚    β”‚  β”‚
β”‚  β”‚  β”‚  :80     β”‚    β”‚  :443    β”‚    β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚  β”‚
β”‚  β”‚                                   β”‚  β”‚
β”‚  β”‚  No network isolation             β”‚  β”‚
β”‚  β”‚  Direct host network access       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use Cases: - High network performance (no NAT overhead) - Network monitoring tools - Services needing host network features

Limitations: - No network isolation - Port conflicts with host - Can't run multiple containers on same port

# Run container with host network
docker run -d \
  --name nginx-host \
  --network host \
  nginx

# Container listens on host's port 80 directly
# No -p flag needed (ignored if specified)

# Check listening ports
netstat -tlnp | grep 80
# tcp  0  0  0.0.0.0:80  0.0.0.0:*  LISTEN  12345/nginx

Performance Comparison

# Bridge network (with NAT)
docker run --rm --network bridge alpine ping -c 4 8.8.8.8
# avg RTT: ~0.5ms overhead

# Host network (no NAT)
docker run --rm --network host alpine ping -c 4 8.8.8.8
# avg RTT: native host performance

None Network

Complete network isolation.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           None Network                   β”‚
β”‚                                          β”‚
β”‚        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚        β”‚  Container   β”‚                  β”‚
β”‚        β”‚              β”‚                  β”‚
β”‚        β”‚  No network  β”‚                  β”‚
β”‚        β”‚  interface   β”‚                  β”‚
β”‚        β”‚              β”‚                  β”‚
β”‚        β”‚  Only: lo    β”‚                  β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β”‚                                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use Cases: - Complete network isolation - Custom network stack implementation - Testing scenarios

# Run container with no network
docker run -d \
  --name isolated \
  --network none \
  alpine sleep 3600

# Verify no network interfaces (except loopback)
docker exec isolated ip addr
# 1: lo: <LOOPBACK,UP,LOWER_UP>
#     inet 127.0.0.1/8 scope host lo

4. Overlay Networks

Overlay networks enable multi-host container communication in Docker Swarm.

Overlay Network Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Overlay Network                           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚    Host 1           β”‚      β”‚    Host 2           β”‚      β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚      β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚      β”‚
β”‚  β”‚  β”‚ Container A  β”‚   │◄────►│  β”‚ Container B  β”‚   β”‚      β”‚
β”‚  β”‚  β”‚ 10.0.0.2     β”‚   β”‚VXLAN β”‚  β”‚ 10.0.0.3     β”‚   β”‚      β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚Tunnelβ”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚      β”‚
β”‚  β”‚                     β”‚      β”‚                     β”‚      β”‚
β”‚  β”‚  Physical: 192.168.1.10    β”‚  Physical: 192.168.1.20  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                              β”‚
β”‚  Overlay subnet: 10.0.0.0/24                                β”‚
β”‚  Underlay network: 192.168.1.0/24                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Creating Overlay Networks

# Initialize Swarm (required for overlay networks)
docker swarm init --advertise-addr 192.168.1.10

# Create overlay network
docker network create \
  --driver overlay \
  --subnet 10.0.9.0/24 \
  my-overlay

# Create with encryption
docker network create \
  --driver overlay \
  --opt encrypted \
  --subnet 10.0.10.0/24 \
  secure-overlay

# Create attachable overlay (for standalone containers)
docker network create \
  --driver overlay \
  --attachable \
  --subnet 10.0.11.0/24 \
  attachable-overlay

Deploying Services on Overlay Network

# Create service on overlay network
docker service create \
  --name web \
  --network my-overlay \
  --replicas 3 \
  nginx

# Create backend service
docker service create \
  --name api \
  --network my-overlay \
  --replicas 2 \
  myapi:latest

# Services can communicate by name across hosts
docker exec <web-container> curl http://api:8080

Docker Compose with Overlay (Swarm Stack)

# docker-compose.yml
version: '3.8'

services:
  web:
    image: nginx
    deploy:
      replicas: 3
    networks:
      - frontend

  api:
    image: myapi:latest
    deploy:
      replicas: 2
    networks:
      - frontend
      - backend

  db:
    image: postgres
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    networks:
      - backend
    volumes:
      - db-data:/var/lib/postgresql/data

networks:
  frontend:
    driver: overlay
  backend:
    driver: overlay
    driver_opts:
      encrypted: "true"

volumes:
  db-data:
# Deploy stack
docker stack deploy -c docker-compose.yml myapp

# List networks
docker network ls
# NETWORK ID     NAME              DRIVER    SCOPE
# abc123def456   myapp_frontend    overlay   swarm
# def789ghi012   myapp_backend     overlay   swarm

Overlay Network Encryption

# Create encrypted overlay
docker network create \
  --driver overlay \
  --opt encrypted=true \
  --subnet 10.0.20.0/24 \
  encrypted-net

# IPsec encrypts VXLAN traffic between nodes
# Performance impact: ~10-20% overhead

5. Network Configuration

Custom Subnet and Gateway

# Create network with custom IPAM
docker network create \
  --driver bridge \
  --subnet 172.30.0.0/16 \
  --gateway 172.30.0.1 \
  --ip-range 172.30.5.0/24 \
  --aux-address "my-router=172.30.1.1" \
  custom-net

MTU Configuration

# Set MTU (Maximum Transmission Unit)
docker network create \
  --driver bridge \
  --opt com.docker.network.driver.mtu=1450 \
  low-mtu-net

# Useful for:
# - VPN/overlay networks (avoid fragmentation)
# - Cloud environments (GCP: 1460, AWS: 9001 for jumbo frames)

IPv6 Support

# Enable IPv6 in daemon.json
# /etc/docker/daemon.json
{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64"
}

# Restart Docker
sudo systemctl restart docker

# Create network with IPv6
docker network create \
  --ipv6 \
  --subnet 172.31.0.0/16 \
  --subnet 2001:db8:2::/64 \
  ipv6-net

Network Driver Options

# Bridge options
docker network create \
  --driver bridge \
  --opt com.docker.network.bridge.name=my-bridge \
  --opt com.docker.network.bridge.enable_icc=true \
  --opt com.docker.network.bridge.enable_ip_masquerade=true \
  my-configured-net

Common Options: - com.docker.network.bridge.name: Custom bridge interface name - com.docker.network.bridge.enable_icc: Inter-container communication (default: true) - com.docker.network.bridge.enable_ip_masquerade: NAT for external traffic (default: true) - com.docker.network.driver.mtu: MTU size (default: 1500)


6. DNS and Service Discovery

Embedded DNS Server

Docker provides automatic DNS resolution for container names.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         User-Defined Network            β”‚
β”‚                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚   web    β”‚         β”‚   db     β”‚     β”‚
β”‚  β”‚          β”‚         β”‚          β”‚     β”‚
β”‚  β”‚          │──DNS───►│          β”‚     β”‚
β”‚  β”‚          β”‚  query  β”‚          β”‚     β”‚
β”‚  β”‚          β”‚  "db"   β”‚          β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚       β”‚                                 β”‚
β”‚       β”‚ DNS query                       β”‚
β”‚       β–Ό                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚  β”‚  Embedded DNS Server    β”‚           β”‚
β”‚  β”‚  (127.0.0.11:53)        β”‚           β”‚
β”‚  β”‚                         β”‚           β”‚
β”‚  β”‚  web β†’ 172.20.0.2       β”‚           β”‚
β”‚  β”‚  db  β†’ 172.20.0.3       β”‚           β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

DNS Resolution Examples

# Create network and containers
docker network create my-net
docker run -d --name web --network my-net nginx
docker run -d --name db --network my-net postgres

# Test DNS resolution
docker exec web nslookup db
# Server:    127.0.0.11
# Address:   127.0.0.11:53
#
# Name:      db
# Address:   172.20.0.3

# Ping by container name
docker exec web ping -c 2 db
# PING db (172.20.0.3): 56 data bytes
# 64 bytes from 172.20.0.3: seq=0 ttl=64 time=0.123 ms

Custom DNS Configuration

# Run container with custom DNS servers
docker run -d \
  --name custom-dns \
  --dns 8.8.8.8 \
  --dns 8.8.4.4 \
  --dns-search example.com \
  nginx

# Verify DNS configuration
docker exec custom-dns cat /etc/resolv.conf
# nameserver 8.8.8.8
# nameserver 8.8.4.4
# search example.com

Service Discovery in Docker Compose

# docker-compose.yml
version: '3.8'

services:
  web:
    image: nginx
    networks:
      - app-net

  api:
    image: myapi:latest
    environment:
      # Resolve by service name
      - DATABASE_URL=postgresql://db:5432/mydb
    networks:
      - app-net

  db:
    image: postgres
    networks:
      - app-net

networks:
  app-net:
    driver: bridge

DNS Round-Robin (Multiple Containers)

# Create multiple containers with same name (using --network-alias)
docker run -d --name api1 --network my-net --network-alias api myapi:latest
docker run -d --name api2 --network my-net --network-alias api myapi:latest
docker run -d --name api3 --network my-net --network-alias api myapi:latest

# DNS query returns all IPs (round-robin)
docker run --rm --network my-net alpine nslookup api
# Name:      api
# Address:   172.20.0.2
# Address:   172.20.0.3
# Address:   172.20.0.4

7. Port Mapping Advanced

Port Publishing Modes

# Publish to random host port
docker run -d -P nginx
# Maps all EXPOSE ports to random high ports (32768+)

# Publish to specific host port
docker run -d -p 8080:80 nginx

# Publish to specific interface
docker run -d -p 127.0.0.1:8080:80 nginx
# Only accessible from localhost

# Publish UDP port
docker run -d -p 53:53/udp dns-server

# Publish port range
docker run -d -p 5000-5010:5000-5010 multi-port-app

Port Mapping Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Host (192.168.1.100)                   β”‚
β”‚                                                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚              iptables NAT                        β”‚    β”‚
β”‚  β”‚                                                  β”‚    β”‚
β”‚  β”‚  8080 ──► DNAT ──► 172.17.0.2:80               β”‚    β”‚
β”‚  β”‚  8443 ──► DNAT ──► 172.17.0.2:443              β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                          β”‚                               β”‚
β”‚                          β–Ό                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚         Docker Bridge (docker0)                 β”‚    β”‚
β”‚  β”‚                                                  β”‚    β”‚
β”‚  β”‚         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”‚    β”‚
β”‚  β”‚         β”‚   nginx          β”‚                    β”‚    β”‚
β”‚  β”‚         β”‚   172.17.0.2     β”‚                    β”‚    β”‚
β”‚  β”‚         β”‚   :80, :443      β”‚                    β”‚    β”‚
β”‚  β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

External request: http://192.168.1.100:8080
    ↓
NAT translation: 172.17.0.2:80
    ↓
Container receives request on port 80

Docker Compose Port Mapping

# docker-compose.yml
version: '3.8'

services:
  web:
    image: nginx
    ports:
      # Short syntax
      - "8080:80"
      - "8443:443"

      # Long syntax
      - target: 80
        published: 8080
        protocol: tcp
        mode: host

      # Localhost only
      - "127.0.0.1:9090:9090"

      # Port range
      - "5000-5010:5000-5010"

Inspecting Port Mappings

# List port mappings
docker port nginx
# 80/tcp -> 0.0.0.0:8080
# 443/tcp -> 0.0.0.0:8443

# Inspect with docker ps
docker ps --format "table {{.Names}}\t{{.Ports}}"
# NAMES    PORTS
# nginx    0.0.0.0:8080->80/tcp, 0.0.0.0:8443->443/tcp

8. Network Security

Network Isolation

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Network Isolation                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚  frontend-net    β”‚        β”‚  backend-net     β”‚      β”‚
β”‚  β”‚                  β”‚        β”‚                  β”‚      β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚      β”‚
β”‚  β”‚  β”‚  web   β”‚      β”‚        β”‚  β”‚  api   β”‚     β”‚      β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚      β”‚
β”‚  β”‚                  β”‚        β”‚        β”‚         β”‚      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚        β”‚         β”‚      β”‚
β”‚                               β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚      β”‚
β”‚                               β”‚  β”‚  db    β”‚     β”‚      β”‚
β”‚                               β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚      β”‚
β”‚                               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                          β”‚
β”‚  web CANNOT communicate with db directly                β”‚
β”‚  api bridges both networks                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
# docker-compose.yml
version: '3.8'

services:
  web:
    image: nginx
    networks:
      - frontend

  api:
    image: myapi:latest
    networks:
      - frontend
      - backend

  db:
    image: postgres
    networks:
      - backend
    # db is NOT exposed to frontend network

networks:
  frontend:
  backend:
    internal: true  # No external access

Internal Networks

# Create internal network (no external access)
docker network create \
  --internal \
  --subnet 172.40.0.0/16 \
  internal-net

# Containers on this network cannot reach internet
docker run -d --name isolated-db --network internal-net postgres

Inter-Container Communication (ICC)

# Disable ICC (containers can't talk to each other by default)
docker network create \
  --driver bridge \
  --opt com.docker.network.bridge.enable_icc=false \
  restricted-net

# Containers must use port publishing to communicate

Network Policy with iptables

# View Docker iptables rules
sudo iptables -t nat -L -n -v | grep DOCKER

# Block traffic between specific containers (manual iptables)
sudo iptables -I DOCKER-USER -s 172.17.0.2 -d 172.17.0.3 -j DROP

# Allow only specific ports
sudo iptables -I DOCKER-USER -p tcp --dport 5432 -s 172.17.0.2 -j ACCEPT
sudo iptables -I DOCKER-USER -s 172.17.0.2 -j DROP

Encrypted Overlay Networks

# All traffic between nodes is encrypted with IPsec
docker network create \
  --driver overlay \
  --opt encrypted=true \
  secure-overlay

9. Troubleshooting

Network Inspection Commands

# Inspect network details
docker network inspect my-net

# Show containers on network
docker network inspect my-net --format '{{range .Containers}}{{.Name}} {{end}}'

# Show network configuration of container
docker inspect my-container --format '{{json .NetworkSettings.Networks}}'

Testing Connectivity

# Ping between containers
docker exec container1 ping container2

# Test DNS resolution
docker exec container1 nslookup container2

# Test port connectivity
docker exec container1 nc -zv container2 80

# Test with curl
docker exec container1 curl http://container2:8080

Packet Capture

# Capture traffic on docker0 bridge
sudo tcpdump -i docker0 -n

# Capture traffic for specific container
# Find container's veth interface
docker inspect my-container --format '{{.NetworkSettings.SandboxKey}}'
# /var/run/docker/netns/abc123def456

# Enter network namespace and capture
sudo nsenter --net=/var/run/docker/netns/abc123def456 tcpdump -i eth0 -n

# Or use docker exec with tcpdump
docker exec my-container tcpdump -i eth0 -n

Common Network Issues

Issue 1: Container Cannot Reach Internet

# Check DNS configuration
docker exec my-container cat /etc/resolv.conf

# Test DNS resolution
docker exec my-container nslookup google.com

# Test connectivity
docker exec my-container ping 8.8.8.8

# Solution: Check IP masquerading
sudo iptables -t nat -L -n | grep MASQUERADE
# Should see: MASQUERADE  all  --  172.17.0.0/16  0.0.0.0/0

Issue 2: Containers Cannot Communicate by Name

# Only works on user-defined networks, NOT default bridge
# Solution: Create custom network
docker network create my-net
docker network connect my-net container1
docker network connect my-net container2

Issue 3: Port Already in Use

# Find process using port
sudo lsof -i :8080
# or
sudo netstat -tlnp | grep 8080

# Solution: Stop conflicting process or use different port
docker run -d -p 8081:80 nginx

Issue 4: DNS Resolution Slow

# Check embedded DNS server
docker exec my-container cat /etc/resolv.conf
# Should see: nameserver 127.0.0.11

# Test DNS performance
docker exec my-container time nslookup container2

# Solution: Add custom DNS servers if needed
docker run --dns 8.8.8.8 --dns 8.8.4.4 my-image

Network Debugging Tools

# Run debugging container with network tools
docker run -it --rm --network my-net nicolaka/netshoot

# Available tools in netshoot:
# - ping, traceroute, mtr
# - nslookup, dig, host
# - curl, wget, httpie
# - netcat, socat
# - tcpdump, tshark
# - iftop, nethogs
# - ip, ss, netstat, iptables

Viewing Network Logs

# Enable debug logging in Docker daemon
# /etc/docker/daemon.json
{
  "debug": true,
  "log-level": "debug"
}

# Restart Docker
sudo systemctl restart docker

# View logs
sudo journalctl -u docker -f

10. Practice Exercises

Exercise 1: Multi-Tier Application Network

Create a three-tier application with isolated networks.

# docker-compose.yml
version: '3.8'

services:
  nginx:
    image: nginx
    ports:
      - "80:80"
    networks:
      - frontend
    depends_on:
      - app

  app:
    image: node:18
    command: node server.js
    networks:
      - frontend
      - backend
    depends_on:
      - db

  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: secret
    networks:
      - backend

networks:
  frontend:
  backend:
    internal: true

Tasks: 1. Deploy the stack 2. Verify nginx can reach app 3. Verify app can reach db 4. Confirm nginx CANNOT reach db directly 5. Confirm db has no internet access

Exercise 2: Custom Bridge Network with Static IPs

# Create network with specific subnet
docker network create \
  --driver bridge \
  --subnet 172.50.0.0/24 \
  --gateway 172.50.0.1 \
  --ip-range 172.50.0.128/25 \
  static-net

# Run containers with static IPs
docker run -d \
  --name web \
  --network static-net \
  --ip 172.50.0.10 \
  nginx

docker run -d \
  --name api \
  --network static-net \
  --ip 172.50.0.20 \
  myapi:latest

docker run -d \
  --name db \
  --network static-net \
  --ip 172.50.0.30 \
  postgres

Tasks: 1. Verify containers have assigned IPs 2. Test connectivity between containers 3. Document the IP allocation scheme

Exercise 3: DNS Round-Robin Load Balancing

# Create network
docker network create lb-net

# Create multiple backend containers with same alias
for i in 1 2 3; do
  docker run -d \
    --name backend-$i \
    --network lb-net \
    --network-alias backend \
    hashicorp/http-echo -text="Backend $i"
done

# Create client container
docker run -it --rm \
  --network lb-net \
  alpine sh

# Test DNS round-robin
for i in {1..6}; do
  wget -qO- http://backend:5678
done

Expected Output:

Backend 1
Backend 2
Backend 3
Backend 1
Backend 2
Backend 3

Exercise 4: Network Troubleshooting

Given a broken network setup, identify and fix issues.

# broken-compose.yml
version: '3.8'

services:
  web:
    image: nginx
    ports:
      - "80:80"
    networks:
      - frontend

  api:
    image: myapi:latest
    environment:
      - DB_HOST=db
    networks:
      - frontend  # BUG: Should be on backend too

  db:
    image: postgres
    networks:
      - backend

networks:
  frontend:
  backend:

Tasks: 1. Deploy and identify why api cannot reach db 2. Fix network configuration 3. Verify all services can communicate correctly 4. Document the issue and solution

Exercise 5: Secure Multi-Host Network

# On host1 (manager)
docker swarm init --advertise-addr 192.168.1.10

# Create encrypted overlay network
docker network create \
  --driver overlay \
  --opt encrypted=true \
  --attachable \
  secure-overlay

# Deploy service
docker service create \
  --name web \
  --network secure-overlay \
  --replicas 3 \
  nginx

# On host2 (worker)
docker swarm join --token <token> 192.168.1.10:2377

# Verify service spans both hosts
docker service ps web

Tasks: 1. Set up 2-node Swarm cluster 2. Create encrypted overlay network 3. Deploy service across nodes 4. Capture traffic and verify encryption 5. Test cross-host container communication

Exercise 6: Network Performance Testing

# Create test network
docker network create perf-net

# Run iperf3 server
docker run -d \
  --name iperf-server \
  --network perf-net \
  networkstatic/iperf3 -s

# Run iperf3 client (bridge network)
docker run --rm \
  --network perf-net \
  networkstatic/iperf3 -c iperf-server -t 30

# Run iperf3 client (host network)
docker run --rm \
  --network host \
  networkstatic/iperf3 -c <host-ip> -t 30

Tasks: 1. Measure bandwidth on bridge network 2. Measure bandwidth on host network 3. Compare results and document overhead 4. Test with different MTU sizes


Summary

In this lesson, you learned:

  • Docker network drivers: bridge, host, overlay, macvlan, none
  • User-defined bridge networks with automatic DNS resolution
  • Host network for performance and none network for isolation
  • Overlay networks for multi-host communication in Swarm
  • Custom network configuration: subnets, gateways, IP ranges, MTU
  • DNS and service discovery with embedded DNS server
  • Advanced port mapping and publishing options
  • Network security: isolation, internal networks, encryption
  • Troubleshooting tools and techniques for network debugging

Key Takeaways: - Always use user-defined networks for automatic DNS resolution - Isolate services with multiple networks for security - Use overlay networks with encryption for multi-host deployments - Leverage embedded DNS for service discovery - Monitor and troubleshoot with proper tooling

Next Steps: - Implement network policies for production environments - Explore service mesh solutions (Istio, Linkerd) for advanced networking - Learn about CNI plugins for Kubernetes - Study network performance optimization techniques


Previous: 10_CI_CD_Pipelines | Next: 12_Security_Best_Practices

to navigate between lessons