Skip to content

1.10 Docker Networking

Overview

Docker networking controls how containers communicate with each other, with the host, and with the outside world. Docker creates three networks automatically on installation: bridge, host, and none.

Abstract

Every container is attached to a network at runtime. The default bridge network gives containers private internal IPs and allows port mapping for external access. The host network removes isolation between container and host. The none network fully isolates a container. User-defined bridge networks allow custom subnets and DNS-based container-to-container communication. Docker's embedded DNS server (127.0.0.11) enables containers to resolve each other by name rather than IP.


Why It Matters in Production

  • Containers need to communicate (web β†’ database, service β†’ cache) without hardcoding IPs that change on restart
  • Network isolation prevents unintended cross-container access in multi-tenant or microservice environments
  • Port mapping and host network mode determine how services are exposed externally
  • Understanding Docker DNS is essential β€” container IPs are dynamic, names are stable

Default Networks

Docker creates three networks automatically on installation:

Network Command Behaviour
bridge docker run ubuntu Default. Private internal network (172.17.x.x). Containers communicate via internal IP. Requires port mapping for external access.
none docker run ubuntu --network=none No network interface. Fully isolated β€” no external or inter-container access.
host docker run ubuntu --network=host Shares the host's network stack. No port mapping needed, but ports are shared across all containers.

Bridge Network

The default bridge network (docker0) assigns IPs in the 172.17.0.0/16 range:

Docker Host
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Web (172.17.0.2)              β”‚
β”‚  Web (172.17.0.3)              β”‚
β”‚  Web (172.17.0.4)              β”‚
β”‚  Web (172.17.0.5)              β”‚
β”‚        ↕ docker0 (172.17.0.1) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Containers on the default bridge can reach each other via internal IP. To expose a container externally, map a port:

docker run -p 8080:5000 my-web-app

Host Network

The container shares the host's network directly β€” no isolation, no port mapping required:

docker run --network=host my-web-app
# Port 5000 in the container is immediately accessible as port 5000 on the host

Host Network Limitation

Because all containers share the host's ports, you cannot run two containers that bind the same port when using --network=host.

None Network

docker run --network=none my-app
# Container has no network interface β€” completely isolated

User-Defined Networks

By default, Docker only creates one internal bridge network. To isolate groups of containers on separate internal networks, create custom networks:

docker network create \
  --driver bridge \
  --subnet 182.18.0.0/16 \
  custom-isolated-network
Docker Host
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Web (172.17.0.2) ─── docker0 (172.17.0.1)           β”‚  ← default bridge
β”‚  Web (172.17.0.4)                                     β”‚
β”‚                                                       β”‚
β”‚  Web (182.18.0.3) ─── docker0 (182.18.0.1)           β”‚  ← custom network
β”‚  Web (182.18.0.2)                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Containers on different networks are isolated β€” they cannot communicate unless explicitly connected.

List Networks

docker network ls
NETWORK ID     NAME                       DRIVER    SCOPE
dba0fb9370fe   bridge                     bridge    local
46d476b87cd9   customer-isolated-network  bridge    local
6de685cec1ce   docker_gwbridge            bridge    local
e29d188b4e47   host                       host      local
zmzho7vsb9rm   ingress                    overlay   swarm
d9f1169510d6   none                       null      local
d371b4009142   simplewebappdocker_default bridge    local

Inspecting Container Network Settings

docker inspect blissful_hopper

Look for the NetworkSettings section:

"NetworkSettings": {
  "Bridge": "",
  "Gateway": "172.17.0.1",
  "IPAddress": "172.17.0.6",
  "MacAddress": "02:42:ac:11:00:06",
  "Networks": {
    "bridge": {
      "Gateway": "172.17.0.1",
      "IPAddress": "172.17.0.6",
      "MacAddress": "02:42:ac:11:00:06"
    }
  }
}

Embedded DNS

Docker includes a built-in DNS server that runs at 127.0.0.11 on every Docker host. Containers can resolve each other using container names instead of IP addresses.

Docker Host
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  web (172.17.0.2)   mysql (172.17.0.3)  β”‚
β”‚          ↕ docker0 (172.17.0.1)         β”‚
β”‚                                         β”‚
β”‚          DNS Server (127.0.0.11)        β”‚
β”‚          web   β†’ 172.17.0.2             β”‚
β”‚          mysql β†’ 172.17.0.3             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use container names in application connection strings β€” not IPs:

# Don't use β€” IP may change on restart
mysql.connect("172.17.0.3")

# Do use β€” resolved by Docker DNS
mysql.connect("mysql")

DNS works reliably on user-defined networks

Docker's embedded DNS resolves container names on user-defined bridge networks. On the default bridge network, name resolution is not guaranteed β€” use custom networks for production service discovery.


Example Commands

docker run nginx
# Gets IP in 172.17.0.x range; accessible internally only
docker run --network=host nginx
# Port 80 on container = port 80 on host, no mapping needed
docker run --network=none busybox
# No network access at all
docker network create \
  --driver bridge \
  --subnet 182.18.0.0/16 \
  custom-isolated-network
docker run --network=custom-isolated-network nginx
docker network inspect bridge

How Docker Implements Networking

Docker uses Linux network namespaces to isolate each container's network stack, and virtual Ethernet pairs (veth) to connect containers to the bridge. Each container sees its own network interface, routing table, and IP stack β€” fully isolated from other containers at the kernel level.


Best Practices

Best Practices

  • Always use user-defined bridge networks for multi-container applications β€” they support DNS-based name resolution, unlike the default bridge.
  • Reference services by container name, not IP β€” IPs are reassigned on restart, names are stable.
  • Use --network=none for containers that process data with no need for network access (batch jobs, transformations) to reduce attack surface.
  • Segment unrelated workloads onto separate custom networks to enforce isolation without firewall rules.
  • Use Docker Compose β€” it automatically creates a user-defined network per project and wires up DNS for all services.

Security Best Practices

Security

  • Avoid --network=host in production unless absolutely required β€” it removes all network isolation and exposes the container to the full host network stack.
  • Do not rely on the default bridge network for service discovery β€” it does not provide reliable DNS resolution between containers by name.
  • Use custom networks to isolate sensitive services β€” a database container should only be on a network shared with the app that needs it, not the default bridge shared by all containers.
  • Restrict inter-container traffic by not placing untrusted containers on the same network.
  • Avoid hardcoding internal IPs in application configs β€” use DNS names that Docker resolves dynamically.

Do and Don't

βœ… Do ❌ Don't
Use user-defined networks for multi-container apps Rely on the default bridge for DNS name resolution
Connect containers by name (mysql, redis) Hardcode container IPs in application configs
Use --network=none for isolated workloads Use --network=host unless there is a specific need
Inspect network settings with docker inspect Guess which IP a container has after a restart
Create per-application custom networks Put all containers on one shared bridge

Common Mistakes

Common Mistakes

  • Using default bridge and expecting DNS to work β€” the default bridge network does not support container name resolution; use a user-defined network.
  • Hardcoding container IPs β€” IPs from the 172.17.x.x pool are reassigned dynamically; always use container names.
  • Running two services on the same port with --network=host β€” since the host's port namespace is shared, only one container can bind a given port at a time.
  • Not inspecting network settings after deploy β€” docker inspect is the first tool to reach for when containers cannot communicate.
  • Forgetting to attach a container to the right network β€” a container only resolves names of other containers on the same network.

Troubleshooting

# List all networks
docker network ls

# Inspect a network (see connected containers and subnet)
docker network inspect bridge

# Inspect a container's IP and network attachment
docker inspect <container_name> | grep -A 20 '"NetworkSettings"'

# Test connectivity between containers (exec into one)
docker exec -it web ping mysql

# Check DNS resolution inside a container
docker exec -it web nslookup mysql

# Attach a running container to an additional network
docker network connect custom-isolated-network web

# Disconnect a container from a network
docker network disconnect bridge web

# Remove an unused network
docker network rm custom-isolated-network

Quick Recap

  • Docker creates three default networks: bridge (default), host, none
  • The default bridge network assigns IPs in 172.17.0.0/16; containers communicate via internal IP
  • host network removes isolation β€” container shares the host's ports directly
  • none network fully isolates a container
  • User-defined networks allow custom subnets and enable DNS-based name resolution
  • Docker's embedded DNS server runs at 127.0.0.11 β€” containers resolve each other by name
  • Use docker network create, docker network ls, and docker inspect to manage and debug networks
  • Docker networking uses Linux network namespaces and virtual Ethernet pairs under the hood

Interview / Revision Notes

  • What are the three default Docker networks? bridge, host, none
  • Default network for a container? bridge β€” IP assigned in the 172.17.0.0/16 range
  • How do containers talk to each other on bridge? Via internal IPs or container names (on user-defined networks)
  • What is the Docker embedded DNS address? 127.0.0.11
  • Why not use container IPs for service discovery? IPs can change on restart; container names are stable and resolved by DNS
  • Difference between bridge and host network? Bridge isolates the container with its own IP; host shares the host's network stack with no isolation
  • How to create a custom network? docker network create --driver bridge --subnet <CIDR> <name>
  • How does Docker implement network isolation? Linux network namespaces per container, connected via virtual Ethernet (veth) pairs
  • When would you use --network=none? For batch/data processing containers that require no network access
  • How to inspect a container's network settings? docker inspect <container> β€” look at NetworkSettings