Skip to main content

Docker Networking

Containers are isolated by default. Networking is how they talk to each other and the outside world.


Network Drivers Overview​

DriverScopeUse Case
bridgeSingle hostDefault. Containers on same host communicate.
hostSingle hostContainer shares host's network stack.
overlayMulti-hostDocker Swarm / multi-node communication.
noneSingle hostComplete network isolation.
macvlanSingle hostAssign MAC address β€” container looks like physical device.
ipvlanSingle hostIP-level control without MAC assignment.

Bridge Network (Default)​

When you run docker run myapp, Docker attaches it to the default bridge network.

Host Machine
β”œβ”€ eth0 (172.31.0.1) β€” real network interface
└─ docker0 (172.17.0.1) β€” virtual bridge
β”œβ”€ container-A (172.17.0.2)
β”œβ”€ container-B (172.17.0.3)
└─ container-C (172.17.0.4)
# Inspect the default bridge
docker network inspect bridge

# Containers on default bridge can reach each other by IP
# but NOT by name β€” name-based DNS only works on user-defined bridges

# Test connectivity between containers
docker run -d --name container-a nginx
docker run --rm -it ubuntu bash
$ ping 172.17.0.2 # Works (by IP)
$ ping container-a # FAILS on default bridge β€” no DNS
# Create custom network
docker network create --driver bridge my-network

# Attach containers at run time
docker run -d --name api --network my-network myapp:1.0.0
docker run -d --name db --network my-network postgres:16
docker run -d --name cache --network my-network redis:7-alpine

# Now containers can communicate by SERVICE NAME
docker exec -it api bash
$ ping db # βœ… Works β€” DNS resolves "db" to db's IP
$ ping cache # βœ… Works
$ curl http://api:8080/health # βœ… Works

User-defined bridge vs default bridge:

FeatureDefault bridgeUser-defined bridge
DNS (by name)βŒβœ…
Automatic DNSβŒβœ…
Network isolation❌ (all containers share)βœ… (only connected containers)
Configurable CIDRβŒβœ…

Host Network​

Container shares the host's network namespace. No NAT. Best performance.

docker run --network host nginx
# nginx listens on port 80 of the HOST directly
# No -p flag needed (or possible)
Host Network Mode:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Host OS β”‚
β”‚ eth0: 192.168.1.100 β”‚
β”‚ β”‚
β”‚ Container (--network host) β”‚
β”‚ Shares: 192.168.1.100 β€” same IP! β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use cases: High-performance networking, where NAT overhead matters (monitoring agents, network tools).
Limitation: Only available on Linux hosts. Not available on Docker Desktop (macOS/Windows).


None Network​

Complete network isolation. No interfaces except loopback.

docker run --network none myapp
# Container has no network access at all
# Useful for: batch processing, security-sensitive workloads

Port Publishing​

Host Machine Container
:8080 ──────────────────→ :8080
:5432 ──────────────────→ :5432
# -p host_port:container_port
docker run -p 8080:8080 myapp # Bind on all interfaces
docker run -p 127.0.0.1:8080:8080 myapp # Localhost only (secure)
docker run -p 0.0.0.0:8080:8080 myapp # All interfaces (explicit)
docker run -p 8080:8080/udp myapp # UDP port

# -P: publish ALL EXPOSE'd ports to random host ports
docker run -P myapp
docker port myapp # β†’ 0.0.0.0:32768 β†’ 8080/tcp

# Multiple ports
docker run -p 8080:8080 -p 9090:9090 -p 5701:5701 myapp

View Port Mappings​

docker port my-api
# 8080/tcp -> 0.0.0.0:8080
# 9090/tcp -> 0.0.0.0:9090

docker ps --format "table {{.Names}}\t{{.Ports}}"

DNS Resolution in Docker​

Docker has a built-in DNS server at 127.0.0.11 for user-defined networks.

Container "api" wants to reach "db":
1. api β†’ DNS query for "db" β†’ Docker internal DNS (127.0.0.11)
2. Docker DNS β†’ resolves "db" to its container IP
3. api β†’ connects to db's IP

Container aliases:
docker run --network my-net --network-alias primary-db postgres
docker run --network my-net --network-alias primary-db --network-alias pg postgres
# Both "primary-db" and "pg" resolve to the same container

Overlay Network (Multi-Host / Docker Swarm)​

Used when containers run on different physical or virtual machines.

Machine A Machine B
container-1 container-2
container-3
↓ ↓
overlay network (VXLAN tunnel across hosts)
└─── container-1 ←──────────→ container-2 β”€β”€β”€β”˜
(transparent β€” looks like same network)
# Only available in Docker Swarm mode
docker swarm init
docker network create --driver overlay --attachable my-overlay
docker service create --network my-overlay myapp

Container-to-Container Communication Patterns​

Pattern 1: Shared User-Defined Network​

docker network create app-net

docker run -d \
--name postgres \
--network app-net \
-e POSTGRES_PASSWORD=secret \
postgres:16-alpine

docker run -d \
--name api \
--network app-net \
-e SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/mydb \
myapp:1.0.0
# "api" resolves "postgres" by name β†’ connects to DB container

Pattern 2: Connect Container to Multiple Networks​

docker network create frontend-net
docker network create backend-net

docker run -d --name nginx --network frontend-net nginx
docker run -d --name api --network backend-net myapp

# Connect api to both networks
docker network connect frontend-net api
# Now: nginx can reach api (frontend-net), api can reach db (backend-net)
# nginx cannot reach db directly (different network)

Networking in Docker Compose​

Docker Compose automatically creates a network and uses service names as DNS hostnames.

# docker-compose.yml
services:
api:
build: .
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/mydb
SPRING_REDIS_HOST: redis
networks:
- backend
depends_on:
postgres:
condition: service_healthy

postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: mydb
POSTGRES_PASSWORD: secret
networks:
- backend
# NOT exposed to host β€” only accessible within backend network

redis:
image: redis:7-alpine
networks:
- backend
# NOT exposed to host

nginx:
image: nginx:alpine
ports:
- "80:80" # ← Only nginx exposed to internet
networks:
- frontend
- backend # ← nginx is in both networks (bridges them)

networks:
frontend: # Internet-facing
backend: # Internal only
internal: true # No internet access from backend network
Internet β†’ nginx (frontend + backend) β†’ api (backend) β†’ postgres (backend)
β†’ redis (backend)
Internet CANNOT reach postgres or redis directly β€” they're on internal backend network only.

Useful Networking Commands​

# See which network a container is on
docker inspect my-api --format '{{json .NetworkSettings.Networks}}' | jq

# Get container IP in a specific network
docker inspect my-api \
--format '{{.NetworkSettings.Networks.my-network.IPAddress}}'

# List all networks
docker network ls

# See all containers connected to a network
docker network inspect my-network \
--format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'

# Test DNS from inside container
docker exec -it api sh -c "nslookup postgres"
docker exec -it api sh -c "wget -qO- http://postgres:5432"
docker exec -it api sh -c "nc -zv postgres 5432" # Check port open

Troubleshooting Network Issues​

# Container can't reach another by name?
# β†’ Check they're on the SAME user-defined network
docker inspect container-a | grep NetworkMode
docker inspect container-b | grep NetworkMode

# Container can't reach internet?
# β†’ Check DNS config inside container
docker exec container-a cat /etc/resolv.conf
docker exec container-a ping 8.8.8.8 # IP works?
docker exec container-a ping google.com # DNS works?

# Port not accessible from host?
docker ps | grep 8080 # Is port mapped?
docker port my-api # What host port?
# Check if binding to 127.0.0.1 (localhost only) vs 0.0.0.0

# Inspect full network config
docker network inspect bridge

Interview Questions​

  1. What is the default Docker network driver and what are its limitations?
  2. What is the difference between a user-defined bridge and the default bridge?
  3. How do containers resolve each other by name?
  4. When would you use --network host mode?
  5. What does -p 127.0.0.1:8080:8080 do vs -p 8080:8080?
  6. How does Docker Compose handle networking between services?
  7. How do you isolate the database container so it's not accessible from the internet in a Docker Compose setup?
  8. What is an overlay network and when is it needed?