Docker DNS — How Containers Find Each Other by Name
What Is Docker DNS in Simple Terms?
When a container wants to reach another container, it needs to know its IP address. But container IPs change every time a container restarts. Docker's embedded DNS server solves this — it automatically assigns each container a DNS hostname matching its container name, and updates the DNS record every time the container restarts with a new IP.
Containers use Docker DNS automatically on user-defined networks. On the default bridge network, there is no DNS — containers are on their own.
◈ DIAGRAM
+------------------------------------------+| Container: payment-api || Needs to reach: postgres || || /etc/resolv.conf: || nameserver 127.0.0.11 <- Docker DNS || || Query: postgres -> 127.0.0.11 -> 172.18.0.3|| postgres restarts -> new IP 172.18.0.4 || Query: postgres -> 127.0.0.11 -> 172.18.0.4|| Same name, automatically updated IP |+------------------------------------------+How Docker DNS Works
Bash
# Create user-defined networkdocker network create payment-network # Run containers on itdocker run -d --name api --network payment-network node:20-alpine sleep 3600docker run -d --name db --network payment-network postgres:15 \ -e POSTGRES_PASSWORD=secret # Check DNS config inside the containerdocker exec api cat /etc/resolv.conf# nameserver 127.0.0.11 <- Docker's embedded DNS# options ndots:0 # Resolve db by namedocker exec api nslookup db# Server: 127.0.0.11# Name: db# Address: 172.18.0.3 # Restart db — it gets a new IPdocker restart dbdocker exec api nslookup db# Name: db# Address: 172.18.0.4 <- updated automaticallyDNS in Docker Compose
YAML
version: "3.8"services: payment-api: environment: DB_HOST: postgres # service name = DNS hostname REDIS_HOST: redis # works automatically in Compose postgres: image: postgres:15 redis: image: redis:7-alpine# Compose auto-creates a user-defined network# All services resolve each other by service nameNetwork Aliases
Bash
# Give a container additional DNS namesdocker run -d \ --name postgres-primary \ --network app-network \ --network-alias db \ --network-alias database \ postgres:15 -e POSTGRES_PASSWORD=secret # Now reachable by three names:# postgres-primary, db, databasedocker exec api ping db # worksdocker exec api ping database # worksDefault Bridge Has No DNS
Bash
# Default bridge — no DNSdocker run -d --name web nginxdocker run -d --name api node:20-alpine sleep 3600 docker exec api nslookup web# ping: bad address 'web' <- FAILS — no DNS on default bridge # Fix: create user-defined networkdocker network create app-networkdocker network connect app-network webdocker network connect app-network apidocker exec api nslookup web # now worksCOMMON MISTAKE / WARNING**Common Mistake:** Hardcoding container IP addresses in application config. Container IPs change on every restart. Always use container names (on user-defined networks) or service names (in Compose) — Docker DNS resolves them to the current IP automatically.