The container network model & drivers

CNM, bridge, host, macvlan, overlay.

Intermediate14 min · lesson 11 of 30

Docker networking follows the Container Network Model (CNM): a container gets a network sandbox (its own network namespace), which attaches to one or more networks through endpoints, and a network driver implements each network. Which driver a network uses decides the container’s reachability and isolation, so the driver mental model is the thing to get straight — everything else is detail hanging off it.

The network drivers
single-host
bridge
default — private virtual net + NAT
host
shares the host stack, no isolation
none
no networking at all
multi-host / special
overlay
spans nodes — Swarm services
macvlan
a real MAC/IP on the physical LAN
bridge for most things, overlay for Swarm across nodes, macvlan when a container must look like a LAN device.

bridge is the default: a private virtual network on one host with NAT out to the world. host removes the network namespace so the container shares the host’s interfaces — fastest, but no isolation and no port mapping. none gives no connectivity, for batch jobs that need none. overlay spans hosts (Swarm). macvlan gives the container its own MAC and IP on the physical network. Create your own bridge rather than the default, because a user-defined bridge adds DNS and isolation.

terminal
$ docker network create --driver bridge --subnet 172.30.0.0/24 appnet
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
1a2b3c4d5e6f appnet bridge local
$ docker network inspect appnet -f '{{ .IPAM.Config }}'
[{172.30.0.0/24 172.30.0.1 map[]}]

Scenario: isolate tiers with two networks

You want the web tier reachable from outside and the database reachable only from web — never directly. Put the database on a backend network only, and attach the web container to both a frontend and the backend network. A container can join multiple networks (docker network connect), and it can only reach services on networks it is attached to — so the database, absent from the frontend network, is simply unreachable from there.

terminal
$ docker network create frontend
$ docker network create backend
$ docker run -d --name db --network backend postgres:16 # backend only
$ docker run -d --name web --network frontend -p 80:3000 myapp:1.0
$ docker network connect backend web # web now on BOTH; can reach db
# anything on frontend still cannot see db — it is not on that network

Scenario: a container that needs a real LAN address

A legacy service or a monitoring agent needs to appear as a first-class device on the physical network with its own IP, not hidden behind host NAT. macvlan attaches the container to the host’s physical interface and gives it its own MAC and IP on that subnet. It is powerful, but it requires the NIC in promiscuous mode, is frequently blocked on cloud provider networks, and by default the host itself cannot talk to its own macvlan containers.

terminal
$ docker network create -d macvlan \
--subnet=192.168.1.0/24 --gateway=192.168.1.1 \
-o parent=eth0 lan
$ docker run -d --network lan --ip 192.168.1.50 --name probe nginx:1.27
# probe now answers on 192.168.1.50 like any other box on the LAN
Default bridge has no DNS; host has no isolation
Two traps: the default bridge network deliberately lacks name resolution, so containers there cannot find each other by name — always use a user-defined bridge (or Compose, which makes one). And host networking removes network isolation entirely, letting the container bind any host port and see all host traffic — fast, but reserve it for cases that genuinely need it.