Multi-Container Networking: Mastering Docker Internal DNS
Learn how Docker handles internal networking, DNS resolution, and service isolation. Master container-to-container communication with real-world examples.

Previously in this course, we explored Defining Service Relationships in Docker Compose, where we ensured services started in the correct order. In this lesson, we add the "glue" that allows those services to talk to each other: Multi-Container Networking.
When you run multiple containers—like an application and a database—they need a private, secure way to exchange data without exposing themselves to the public internet. Docker solves this by creating isolated virtual networks that provide built-in service discovery via internal DNS.
Understanding the Docker Bridge Network
By default, when you run docker-compose up, Docker creates a user-defined bridge network for your project. Think of a bridge network as a virtual switch inside your host machine. Any container attached to this network can communicate with any other container on the same network using their service names.
Because these networks are isolated, containers from one project cannot "see" or ping containers from another project unless you explicitly configure them to share a network. This is a crucial security feature: by default, your production database container is unreachable by a rogue container you might be running for an experiment.
How Internal DNS Works
You don't need to hardcode IP addresses (which change every time a container restarts). Instead, Docker provides an internal DNS server. Every service defined in your docker-compose.yml is automatically registered in this DNS.
If you have a service named db, any other container in the same network can reach it simply by using the hostname db. Docker’s internal resolver intercepts this request and translates it to the correct private IP address within the bridge network.
Worked Example: Ping Between Containers

Let's verify this behavior. Suppose we have a simple docker-compose.yml file:
YAMLservices: web: image: alpine command: sleep infinity db: image: alpine command: sleep infinity
When you run docker compose up -d, Docker starts both containers on the same network. We can now use docker compose exec to enter the web container and ping the db service.
-
Start the services:
docker compose up -d -
Test internal communication:
docker compose exec web ping -c 3 db
You will see output indicating that the web container successfully reached db and received responses. The ping command resolved db to an internal IP address (usually starting with 172.x.x.x) automatically.
Hands-on Exercise
- Add a third service called
cacheto your existing Compose file using thealpineimage. - Bring the stack up.
- From the
webcontainer, run apingto thecacheservice. - Verify that you can also
pingthewebservice from thecachecontainer.
This confirms that your network is fully meshed, allowing bidirectional communication between all services in the stack.
Common Pitfalls
- Relying on IP Addresses: Never use IP addresses in your application code. If a container is recreated, its IP will likely change. Always use the service name as the hostname.
- External vs. Internal Networks: Remember that
localhostinside a container refers to the container itself, not your host machine. If you need to reach a service running directly on your host, usehost.docker.internal(on Docker Desktop). - Forgetting to Link Networks: If you manually define multiple networks in Compose, a container must be added to the same network as its target to communicate with it.
FAQ
Q: Can I reach a container from outside the Docker network?
A: Only if you map ports using the ports directive. Otherwise, the network remains private to the host.
Q: Does internal DNS work if I don't use Docker Compose?
A: It works if you use a user-defined bridge network created with docker network create. It does not work on the default bridge network that Docker creates when you run raw docker run commands.
Recap
Docker simplifies complex infrastructure by providing isolated bridge networks and an automated internal DNS. By using service names as hostnames, your application components can discover and communicate with each other reliably, regardless of their underlying IP addresses. This isolation keeps your services secure by default while providing a robust environment for multi-service applications.
Up next: We will secure our database credentials and API keys by Managing Secret Configuration using environment files.
Work with me

CI/CD Pipeline & Docker Containerization
Ship with confidence: automated CI/CD pipelines and Docker setups so every push is tested and deployed — no more manual, error-prone releases.

Laravel SaaS MVP & Multi-Tenant App Development
Launch your SaaS MVP on Laravel — multi-tenant, subscription-ready, and built by the engineer behind a platform serving 10,000+ paying users.

