Docker containers on different networks can’t talk to each other by default, even if they’re on the same Docker host.

Let’s see this in action. Imagine we have two containers, app1 and db1. app1 needs to connect to db1.

First, we need to set up our networks. We’ll create a custom bridge network called frontend for our application containers and another called backend for our database containers.

docker network create frontend
docker network create backend

Now, let’s launch our containers, attaching them to their respective networks. For demonstration, we’ll use simple alpine containers, but in a real scenario, these would be your application and database images.

docker run -d --name app1 --network frontend alpine sleep infinity
docker run -d --name db1 --network backend alpine sleep infinity

If we try to ping db1 from app1 right now, it will fail:

docker exec app1 ping db1

This is because app1 is on the frontend network and db1 is on the backend network. By default, Docker containers only communicate within the same network.

To enable communication, we have a few options. The most straightforward is to connect both containers to a common network. We can do this by connecting app1 to the backend network, or db1 to the frontend network, or by creating a new network that both join. Let’s add app1 to the backend network.

docker network connect backend app1

Now, app1 is connected to both frontend and backend networks. It can reach containers on the backend network, including db1.

Let’s test the ping again:

docker exec app1 ping db1

This should now succeed. The app1 container, with its multiple network interfaces, can now resolve and reach db1 using its name. Docker’s internal DNS will handle the name resolution for db1 on the backend network.

The mental model here is that Docker networks are like virtual switches. Containers plugged into the same switch can talk to each other directly. If they’re on different switches, they can’t unless you bridge those switches or plug both devices into a common switch.

When you attach a container to multiple networks, Docker configures its routing table so it can reach destinations on any of its attached networks. For name resolution, Docker’s embedded DNS server will provide the IP address of the target container on the specified network.

The key lever you control is which networks your containers are attached to. By default, containers are attached to a bridge network named bridge. When you create custom networks, you gain more granular control over container isolation and communication. You can have networks that are completely isolated, or networks that allow specific groups of containers to communicate.

What most people don’t realize is that when a container is attached to multiple networks, Docker doesn’t automatically prioritize one network for DNS resolution. If you have containers with the same hostname on different networks, or if you’re using docker-compose and have services that could potentially resolve to different IPs based on which network is queried first, you can run into subtle issues. You can explicitly specify the network to use for resolution by appending .<network_name> to the hostname, like db1.backend.

The next concept to explore is how to manage these networks and containers using docker-compose for more complex multi-container applications.

Want structured learning?

Take the full Docker course →