Cloud Tech by Victor
DevOpsAdvanced

Docker Networking

How Docker's bridge, host, and overlay network drivers work, how container DNS resolution happens, and the port-publishing model that trips up most beginners.

Updated 2026-06-153 min read

Overview

Every Docker container runs in its own network namespace by default, connected to a virtual network managed by Docker. The driver you choose for that network, bridge, host, overlay, or none, determines how containers reach each other, how they reach the outside world, and how the outside world reaches them. Most confusion comes from conflating two different questions: "can containers talk to each other" (governed by which Docker network they share) and "can the host or outside world reach a container" (governed by published ports).

Quick Reference

DriverScopeUse case
bridge (user-defined)Single hostDefault for most multi-container apps; gives DNS-based container name resolution
bridge (default)Single hostLegacy default network; no automatic DNS between containers
hostSingle hostShares the host's network stack directly; no isolation, no port mapping needed
overlayMulti-host (Swarm/K8s-adjacent)Container-to-container networking across multiple Docker hosts
noneN/AFully isolates a container from all networking

Syntax

bash
# Create a user-defined bridge network
docker network create app-net

# Run containers attached to it; they can resolve each other by name
docker run -d --name api --network app-net my-api-image
docker run -d --name db --network app-net postgres:16

# Publish a port so the host (and outside world) can reach the container
docker run -d --name api -p 8080:80 --network app-net my-api-image

Examples

yaml
# docker-compose.yml - services on the same compose network resolve
# each other by service name automatically; no manual network needed.
services:
  api:
    build: .
    ports:
      - '8080:80' # host:container - only needed for host/external access
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
javascript
// Inside the `api` container, `db` resolves via Docker's embedded DNS -
// no hardcoded IP address needed.
const client = new Client({ host: 'db', port: 5432 })

Visual Diagram

Common Mistakes

  • Using the legacy default bridge network and expecting containers to resolve each other by name, only user-defined bridge networks get Docker's embedded DNS.
  • Publishing a port with -p purely to let sibling containers talk to each other, unnecessary; they only need to share a network.
  • Assuming host networking is "just faster" without weighing the loss of network isolation and the risk of port collisions with the host itself.
  • Forgetting that containers on different Docker networks cannot reach each other at all unless explicitly connected to a shared network.

Performance

  • Bridge networking adds a small amount of NAT/virtual-interface overhead per packet compared to host networking, usually negligible for typical web workloads, but measurable for very high-throughput, low-latency services.
  • Overlay networks (multi-host) add encapsulation overhead (VXLAN by default) on top of bridge networking, since traffic has to be tunneled between hosts.
  • The none driver has zero networking overhead by definition, useful for batch/offline jobs that need no network access at all.

Best Practices

  • Always use a user-defined bridge network (or Compose's default per-project network) instead of the legacy default bridge, to get name-based service discovery.
  • Only publish ports that genuinely need to be reachable from the host or the internet, internal service-to-service traffic does not need it.
  • Reach for host networking only when its specific performance characteristics are required and the isolation trade-off is acceptable.
  • Use overlay networks (or a Kubernetes CNI) when containers need to communicate across multiple physical or virtual hosts.

Interview questions

What is the default Docker network driver and how does container-to-container communication work on it?

The default is the bridge driver, Docker creates a private virtual network on the host, and each container gets its own network namespace with a virtual ethernet interface connected to that bridge. Containers on the same user-defined bridge network can reach each other by container name, because Docker runs an embedded DNS server that resolves container names to their internal IPs on that network. Containers on the default (unnamed) bridge network do not get this automatic DNS resolution, only user-defined bridge networks provide it.

Why does publishing a port with -p 8080:80 not automatically make the container reachable from other containers?

-p (or --publish) maps a port on the Docker host to a port inside the container, specifically for reaching the container from outside the Docker network, from the host machine or the internet. Other containers on the same user-defined network do not need that mapping at all; they can reach the container directly on its internal port via the container's name and internal port, because they share the internal bridge network. Publishing a port is about host-to-container access, not container-to-container access.

What is the difference between the bridge and host network drivers?

With the bridge driver (the default), a container gets its own isolated network namespace and IP address, and ports must be explicitly published to be reachable from the host. With the host driver, the container shares the host's network namespace directly, no isolation, no port publishing needed, the container's ports are the host's ports. Host networking is faster (no NAT/bridge overhead) but sacrifices network isolation, so it is used selectively, not as a default.

References

ShareXLinkedInReddit
Was this page helpful?
Suggest an improvement