DNS and Service Discovery
Docker has a built-in DNS server that lets containers on the same user-defined network find each other by name. Instead of hardcoding IP addresses (which change every time a container restarts), you use service names like db, api, or cache.
How Docker DNS Works
When the api container connects to hostname db, Docker's embedded DNS resolves it to the IP address of the db container on the same network.
Key Rules
| Rule | Detail |
|---|---|
| DNS works on user-defined networks | The default bridge network does not have DNS. Always create your own |
| Names are network-scoped | A container can only resolve names of containers on the same network |
Names come from --name or Compose service names | In Compose, the service key (db, api) becomes the DNS hostname |
| IPs can change | Container IPs change on recreation. Never hardcode IPs -- use names |
Basic Example
# Create a network
docker network create app-net
# Start a database
docker run -d --name db --network app-net postgres:16
# Test DNS resolution from another container
docker run --rm --network app-net alpine:3.20 nslookup db
# Output: Name: db Address: 172.18.0.2
DNS in Docker Compose
In Compose, service names automatically become DNS hostnames on shared networks:
services:
api:
image: my-api:1.0.0
environment:
DB_HOST: db # Use the service name, not an IP
REDIS_HOST: cache
networks: [back]
db:
image: postgres:16
networks: [back]
cache:
image: redis:7-alpine
networks: [back]
networks:
back: {}
The api container can reach db on port 5432 and cache on port 6379 using their service names.
Network Segmentation and DNS Scope
DNS only works within a shared network. Use this to control which services can see each other:
In this setup, web is on both front and back, so it can reach api. But web cannot reach db directly because they do not share a network (unless web is also on back).
Debugging DNS Issues
Most Docker networking problems are actually DNS/discovery problems. Follow this order:
Step 1: Verify Network Membership
# Check what networks a container is on
docker inspect -f '{{json .NetworkSettings.Networks}}' api
# Check which containers are on a network
docker network inspect app-net
If two containers are not on the same network, DNS cannot resolve between them. This is the #1 root cause.
Step 2: Test Name Resolution
# From inside the calling container
docker exec -it api sh
nslookup db
# or
getent hosts db
Step 3: Test Connectivity
# If DNS resolves but connection fails, check if the port is open
docker exec -it api sh
nc -vz db 5432
Quick Diagnostic with a Temp Container
docker run --rm -it --network app-net alpine:3.20 sh
# Inside: nslookup db && nc -vz db 5432
This avoids modifying your running containers.
Common DNS Errors and Fixes
| Error | Likely Cause | Fix |
|---|---|---|
Name not found / NXDOMAIN | Containers are on different networks | Connect both to the same user-defined network |
Connection refused | DNS resolves, but nothing is listening on that port | Check target container is running and listening |
Timeout | Firewall or network policy blocking traffic | Check firewall rules and network configuration |
| Intermittent failures | Startup race (app queries DNS before target is ready) | Add retry logic or depends_on with health checks |
Using localhost between containers | localhost refers to the container itself, not other services | Use the service name instead (db, api) |
Key Takeaways
- Docker DNS works on user-defined networks only. Always create your own network.
- Use service names (container name or Compose service key) instead of IP addresses in application config.
- DNS is network-scoped -- containers must share a network to resolve each other.
- When debugging connectivity, check network membership first, then DNS, then port listening.
- Use temporary debug containers (
docker run --rm -it --network ...) to test without touching production.
What's Next
- Continue to Networking with Compose to design full network topologies for multi-service stacks.