Docker Course
Docker Networking Basics
Two containers are running on the same machine. Your API needs to talk to your database. By default, they can't reach each other — and that's intentional. Docker's networking model is isolated by design and open by configuration. This lesson teaches you how it works and how to connect what needs to be connected.
Networking is the part of Docker that trips up most developers because it's invisible — you can't see the network the way you can see a volume or a container. But once you understand the model, connecting containers becomes as natural as everything else.
Container Network Isolation
Every container gets its own network namespace — a completely isolated network stack with its own IP address, its own network interfaces, its own routing table, and its own set of ports. From inside a container, it looks like a separate machine on its own private network.
Two containers running on the same host cannot communicate with each other by default. This isolation is a security feature — a compromised container can't reach other containers on the same machine unless you explicitly configure it to. Communication has to be deliberately enabled.
The Apartment Building Analogy
Every container is like an apartment in a building. Each apartment has its own door, its own lock, and its own internal space — tenants can't walk into each other's apartments uninvited. To allow two tenants to communicate, you build a shared corridor between their apartments. That corridor is a Docker network. Containers on the same Docker network can talk to each other. Containers on different networks — or no network — cannot.
Docker's Built-in Networks
When Docker installs, it creates three default networks automatically. Every container you start is attached to one of these unless you specify otherwise.
docker network ls
# Lists all networks Docker knows about on this machine
NETWORK ID NAME DRIVER SCOPE 3f8a2c1b4d7e bridge bridge local 1a9b3c5d7e8f host host local 2b4c6d8e0f1a none null local
What just happened?
Three built-in networks appear immediately after installing Docker. bridge is the default — containers without an explicit network are attached here. It allows container-to-container communication via IP address but not by name. host removes network isolation entirely — the container shares the host's network stack directly. none disables all networking — the container has no network interface at all, used for maximum isolation. In practice, you'll create your own custom bridge networks rather than using the default one — and Lesson 18 covers exactly why.
The Default Bridge Network — and Its Limitation
The default bridge network connects all containers that don't specify a network. Containers on it can reach each other by IP address — but not by container name. That's the critical limitation.
IP addresses in Docker are assigned dynamically. Every time a container starts, it might get a different IP. If your API container hardcodes the database container's IP address, it breaks every time the database container restarts and gets a new IP. This is why the default bridge network is considered legacy — and why custom networks with DNS resolution are the correct approach for anything beyond a single throwaway container.
Default bridge network — IP only, no DNS
172.17.0.2
172.17.0.3
172.17.0.4
Containers can ping each other by IP — but if db-container restarts and gets 172.17.0.5, the API breaks. No DNS. No name resolution.
Custom Networks — The Right Way
Custom bridge networks solve the DNS problem completely. Every container on a user-defined network can reach every other container on that network using its container name as a hostname. Docker runs a built-in DNS server that resolves container names automatically — no IP addresses required.
The scenario: You're a DevOps engineer setting up a local development stack with three containers — an API, a PostgreSQL database, and a Redis cache. All three need to communicate with each other. The API needs to reach the database by the hostname db-container and Redis by the hostname redis-cache. Static IPs would break on every restart — custom networks with DNS make this trivial.
# Step 1 — Create a custom bridge network
docker network create app-network
# Docker creates a new bridge network with its own subnet
# Containers on this network can reach each other by container name
# Step 2 — Start all three containers on the same network
docker run -d \
--name db-container \
--network app-network \
-e POSTGRES_PASSWORD=secret123 \
postgres:15-alpine
docker run -d \
--name redis-cache \
--network app-network \
redis:7-alpine
docker run -d \
--name order-api \
--network app-network \
-p 3000:3000 \
order-api:v1.0.0
# All three containers are on app-network
# order-api can now connect to postgres at hostname "db-container"
# and to Redis at hostname "redis-cache" — Docker DNS handles the resolution
d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4 a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2 7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d # Inside order-api container — DNS resolution works automatically: # postgresql://db-container:5432/orders ← connects to the Postgres container # redis://redis-cache:6379 ← connects to the Redis container
What just happened?
All three containers started on app-network. Docker's built-in DNS automatically registered each container's name as a hostname on that network. The API can now connect to PostgreSQL using the connection string postgresql://db-container:5432/orders — the hostname db-container resolves to whatever IP address that container currently has, dynamically. Restart db-container and it gets a new IP — but the hostname still works. No hardcoded IPs, no broken connections after restarts. This is the fundamental advantage of custom networks over the default bridge.
Custom bridge network — DNS by container name
reaches others by name
hostname: db-container
hostname: redis-cache
Container names become hostnames. DNS resolution is automatic. Restart any container and the name still resolves correctly.
Inspecting and Managing Networks
docker network ls # list all networks
docker network inspect app-network # detailed view — which containers are connected
docker network connect app-network nginx-proxy # add a running container to a network
docker network disconnect app-network nginx-proxy # remove a container from a network
docker network rm app-network # delete a network (must have no connected containers)
docker network prune # remove all unused networks
NETWORK ID NAME DRIVER SCOPE
3f8a2c1b4d7e bridge bridge local
9e1f3a5b7c9d app-network bridge local
1a9b3c5d7e8f host host local
2b4c6d8e0f1a none null local
[
{
"Name": "app-network",
"Driver": "bridge",
"Containers": {
"7c8d9e0f...": { "Name": "order-api", "IPv4Address": "172.18.0.4/16" },
"d3e4f5a6...": { "Name": "db-container", "IPv4Address": "172.18.0.2/16" },
"a1b2c3d4...": { "Name": "redis-cache", "IPv4Address": "172.18.0.3/16" }
}
}
]
What just happened?
docker network inspect shows the full topology of the custom network — all three containers listed with their current IP addresses and names. This is how you debug connectivity issues: if a container isn't in the Containers list of the network you expect, it's not reachable by name on that network. The docker network connect command lets you attach a running container to an additional network — a container can be on multiple networks simultaneously, which is how you selectively expose some containers to the outside world while keeping others private.
The Default Bridge Network Has No DNS
A very common gotcha: two containers on the default bridge network cannot reach each other by container name — only by IP. Only user-defined custom networks get Docker's built-in DNS. Any time you need containers to talk to each other by name — which is almost always — create a custom network. The default bridge is fine for single containers that only need external access, nothing more.
Teacher's Note
In Section III you'll use Docker Compose, which automatically creates a custom network for every project and attaches all services to it — so you get DNS for free. But knowing how to do it manually makes you understand exactly what Compose is doing under the hood.
Practice Questions
1. The command used to create a new custom bridge network in Docker is called what?
2. To attach a container to a specific network when running docker run, which flag do you use?
3. To see all containers currently connected to a specific network and their IP addresses, which command do you run?
Quiz
1. Two containers are on Docker's default bridge network. The API container tries to connect to the database container using the hostname db-container but fails. Why?
2. An nginx proxy container needs to reach both a frontend container on frontend-net and a backend API on backend-net. How is this achieved?
3. A security-sensitive container must have absolutely no network access — it should be completely isolated from all networks. Which built-in Docker network achieves this?
Up Next · Lesson 18
Bridge Network
You've created a custom bridge network — now let's go deep on how it works internally, how traffic flows between containers, and how to use network aliases to decouple your containers from their names.