Container Networking
Container Networking
Networking is where most Docker surprises happen in production. A container that works perfectly in isolation silently fails when it tries to reach a database on the same host — or a service in another container — because the developer did not understand how Docker has isolated the network stack. This lesson closes that gap: you will understand every network driver Docker ships with, how port publishing works at the kernel level, and how container DNS lets services find each other by name instead of IP.
How Docker Isolates Networking
Each container gets its own network namespace — a Linux kernel primitive that gives the container a private view of network interfaces, routing tables, and iptables rules. From inside the container, eth0 is its only interface and it has no knowledge of the host's physical NIC or other containers, unless you explicitly connect them. Docker wires namespaces together using one of several network drivers.
The Three Core Network Drivers
bridge (default)
The default driver. Docker creates a virtual Ethernet bridge (docker0) on the host. Each container connected to a bridge network gets a veth pair: one end inside the container namespace, the other end attached to the bridge. Containers on the same bridge can reach each other by IP. Traffic leaving the bridge is NAT-ed by iptables through the host's physical interface.
When you create a user-defined bridge (any bridge other than docker0), Docker also enables an embedded DNS server — containers can resolve each other by container name. The default docker0 bridge does not have this DNS feature, which is why the docs tell you never to rely on --link in production.
docker0 bridge gives containers IPs but no DNS. A user-defined bridge network adds container-name DNS resolution automatically. Always create a named network for multi-container apps — it is the single most important Docker networking habit.
host
With --network host, the container shares the host's network namespace entirely. There is no isolation: eth0 inside the container is literally the host's eth0. No NAT, no port publishing needed. This gives the lowest possible latency (no veth hop, no iptables translation) and is used by performance-critical applications — high-frequency trading, eBPF-based network agents, sidecar proxies like Envoy in some configurations.
--network host works as described. On Docker Desktop for macOS and Windows, the container still runs inside a Linux VM, so --network host gives you the VM's network, not your laptop's. Code that works perfectly on a Linux CI runner may behave differently on a Mac developer machine.
none
The container gets its own namespace but no interfaces are configured — only a loopback (lo). Used for batch jobs that process data from mounted volumes with no network I/O at all, or as a hardened security posture for containers that must not exfiltrate data. You can always attach additional interfaces after the fact with docker network connect.
Port Publishing
A bridge container's IP is private to the host — nothing outside can reach it directly. Port publishing maps a host port to a container port via iptables DNAT rules that Docker manages for you.
When you publish 0.0.0.0:8080->80, Docker inserts an iptables PREROUTING DNAT rule so that any packet arriving on the host's port 8080 is redirected to the container's private IP on port 80. This means the container is reachable from the internet if the host's firewall allows port 8080 — a common cause of unintended exposure. Prefer binding to 127.0.0.1 and using a reverse proxy (Nginx, Caddy) in front, which terminates TLS and controls access.
0.0.0.0 for databases (Postgres, Redis, MongoDB). Bind them to 127.0.0.1 or, better, do not publish them at all — containers on the same user-defined network can reach each other without any published port.
Container DNS on User-Defined Bridge Networks
When containers are on the same user-defined network, Docker's embedded DNS resolver (127.0.0.11) answers queries using container names, service aliases, and network aliases as hostnames. The resolver is injected into each container's /etc/resolv.conf automatically.
This is exactly how Docker Compose wires services together — it creates a shared network and each service is reachable by its service name. Understanding this makes Compose configs far less magical.
Diagram: Bridge Networking
Inspecting and Debugging Networks
Multi-Host Networking: Overlay Networks
Bridge and host networks are single-host constructs. When containers need to communicate across multiple hosts (a Swarm cluster or as a building block before you move to Kubernetes), Docker provides the overlay driver, which creates a distributed virtual network using VXLAN tunnels. Overlay is out of scope for this lesson but worth knowing it exists — the same mental model (user-defined network + DNS by service name) applies, just stretched across hosts.
Production Checklist
- Always use user-defined bridge networks — never rely on the default
docker0bridge or--link. - Do not publish database ports to 0.0.0.0 — keep them internal to the network; only the app/proxy container needs a published port.
- Bind reverse-proxy ports explicitly — use
127.0.0.1:80:80if a host-level proxy (Nginx) is handling TLS termination. - Use container names as hostnames in connection strings; hard-coded IPs break every time a container is recreated.
- Segment networks by trust — a frontend container should not share a network with the database; put a middle-tier API between them.