Docker Networking

Understand Docker bridge, host, and none networks, user-defined networks, DNS-based service discovery, and port publishing with examples.

Containers rarely run alone: a web app talks to a database, a cache, and other services. Docker provides virtual networks that let containers find and reach each other while staying isolated from the outside world unless you explicitly publish ports. Knowing the network drivers and how name resolution works solves most "container cannot connect" problems.

Network Drivers

Driver Behaviour Typical use
bridge Private virtual network on a single host; containers get their own IP Default for standalone containers; user-defined bridges for multi-container apps
host Container shares the host's network stack; no isolation, no port mapping Maximum network performance, or when many ports are needed
none Only a loopback interface Fully isolated containers
overlay Multi-host network (used with Swarm) Services spanning several Docker hosts
macvlan Container gets its own MAC address on the physical network Legacy apps that expect to be directly on the LAN
docker network ls
# NETWORK ID     NAME      DRIVER    SCOPE
# 1a2b3c4d5e6f   bridge    bridge    local
# 7a8b9c0d1e2f   host      host      local
# 3f4e5d6c7b8a   none      null      local

Default Bridge vs User-Defined Bridge

Containers started without --network join the default bridge network. On it, containers can reach each other by IP address only. A user-defined bridge network adds automatic DNS resolution by container name, better isolation, and the ability to attach and detach containers at runtime.

Feature Default bridge User-defined bridge
Resolve containers by name No (IP only) Yes
Isolation from unrelated containers Weaker, all share one network Better, only attached containers
Attach/detach running containers Requires restart docker network connect/disconnect

Container-to-Container Communication

docker network create appnet

docker run -d --name db --network appnet \
  -e POSTGRES_PASSWORD=secret postgres:16

docker run --rm --network appnet postgres:16 \
  pg_isready -h db -U postgres
# db:5432 - accepting connections

The second container reaches the first simply by using the hostname db. Docker's embedded DNS server (at 127.0.0.11 inside the container) resolves container names and network aliases on user-defined networks.

Inside a shared network you use the container's port directly (db:5432). You do not need to publish the port to the host for container-to-container traffic.

Publishing Ports

Publishing makes a container port reachable from outside the Docker network.

docker run -d --name web -p 8080:80 nginx:1.27            # host 8080 -> container 80 (all interfaces)
docker run -d --name web2 -p 127.0.0.1:8081:80 nginx:1.27 # only reachable from the host itself
docker run -d --name web3 -p 80 nginx:1.27                # random host port
docker run -d --name web4 -P nginx:1.27                   # publish all EXPOSEd ports to random ports

docker port web
# 80/tcp -> 0.0.0.0:8080

EXPOSE in a Dockerfile only documents a port; -p is what publishes it.

Host and None Networks

# Host: nginx listens directly on the host's port 80 (-p is ignored)
docker run -d --network host nginx:1.27

# None: no external connectivity
docker run --rm --network none alpine ip addr
# only the "lo" interface is shown

Host networking works on Linux hosts. On Docker Desktop the container shares the network of the Docker VM, not your laptop's, unless host networking is specifically enabled in settings.

Networking in Docker Compose

Compose creates a default network for the project and attaches every service to it. Services reach each other by service name.

services:
  api:
    image: my-api:1.0
    environment:
      DB_HOST: db
    networks: [backend, frontend]
    ports:
      - "8080:8080"

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    networks: [backend]

networks:
  frontend:
  backend:

Here db is only on backend, so containers on frontend cannot reach it.

Inspecting and Debugging Networks

docker network inspect appnet           # subnet, connected containers, IPs
docker inspect -f '{{json .NetworkSettings.Networks}}' db
docker exec -it api sh -c "getent hosts db"   # DNS resolution test
docker network connect appnet existing-container
docker network disconnect appnet existing-container

Common Mistakes

  • Using localhost to reach another container. localhost inside a container is the container itself. Use the service or container name.
  • Relying on container names on the default bridge. Name resolution only works on user-defined networks.
  • Publishing database ports publicly. -p 5432:5432 exposes it on every host interface. Keep it on an internal network or bind to 127.0.0.1.
  • Hard-coding container IPs. They change on restart. Use names.
  • Confusing EXPOSE with -p. EXPOSE does not make a port reachable from the host.

Best Practices

  • Create user-defined networks per application and let Compose manage them.
  • Publish only the ports that must be reachable from outside, and bind to 127.0.0.1 when local access is enough.
  • Segment networks (frontend, backend) so databases are not reachable from public-facing services.
  • Use service names for configuration instead of IP addresses.

Interview Questions

1. What are the main Docker network drivers?

bridge (default, single-host private network), host (shares the host's network stack), none (no networking), overlay (multi-host), and macvlan (container appears as a device on the physical network).

2. How do containers communicate with each other?

When attached to the same user-defined network, they can reach each other by container or service name through Docker's embedded DNS, using the container port directly. On the default bridge they must use IP addresses.

3. What is the difference between EXPOSE and -p?

EXPOSE is documentation (image metadata) saying which port the application uses. -p host:container actually publishes the port on the host so external clients can connect.

4. Why can a container not reach another container using localhost?

Each container has its own network namespace, so localhost refers to the container itself. Use the other container's name on a shared network.

5. When would you use host networking?

When you need native network performance or must expose a large range of ports without mapping each one. The trade-off is losing network isolation and port-mapping flexibility, and it is Linux-oriented.

6. How does service discovery work in Docker Compose?

Compose attaches services to a project network, and Docker's DNS resolves each service name to the IPs of its containers. An app can connect to db:5432 without knowing any IP address.

Summary

  • Bridge is the default driver; user-defined bridges add DNS-based name resolution and better isolation.
  • Containers on the same network talk via names and container ports; publish ports only for external access.
  • host removes isolation, none removes connectivity.
  • localhost inside a container never points to another container.

Continue Learning

Previous: Docker Volumes | Next: Docker Compose

Was this guide helpful?

CodeWithVenu is free to read, with no paywall. If this guide saved you time or helped you prepare, a small voluntary contribution helps me write more practical tutorials, architecture guides, and interview-prep content.