DNS & Service Names
Docker links were the original way to make container A reach container B by name. They are legacy now — modern Docker uses user-defined networks and the embedded DNS server, which gives you the same name-based discovery without legacys footguns (transitive dependencies, alias drift, fragile environment variables).
User-defined networks, embedded DNS, aliases
EXAMPLE
# 1) Create a user-defined bridge network
docker network create shop-net
# 2) Run containers on it — they reach each other by NAME (auto-registered DNS)
docker run -d --name db --network shop-net postgres:16
docker run -d --name redis --network shop-net redis:7
docker run -d --name api --network shop-net \
-e DATABASE_URL=postgres://postgres@db:5432/shop \
-e REDIS_URL=redis://redis:6379 \
my/api:1.0
# 'db' and 'redis' resolve via Dockers embedded DNS at 127.0.0.11. No /etc/hosts hacks.
# 3) Aliases — give a container an extra DNS name on a network
docker network connect --alias primary shop-net db
# Now 'db' AND 'primary' both resolve to the postgres container.
# 4) Multiple networks for segmentation (web tier vs internal tier)
docker network create web-net --driver bridge
docker network create internal --driver bridge --internal # NO external internet
docker run -d --name lb --network web-net -p 80:80 nginx
docker run -d --name api --network web-net --network-alias api my/api:1.0
docker network connect internal api # api ALSO sits on internal
docker run -d --name db --network internal postgres:16
# api can reach db (both on 'internal'), and the LB can reach api (both on 'web-net'),
# but db has no path to the public internet.
# 5) Inspect what is on a network
docker network inspect shop-net --format \
'{{range $k, $v := .Containers}}{{ $v.Name }}: {{ $v.IPv4Address }}\n{{end}}'
# 6) Compose: networks are the default mechanism, links should not appear
# docker-compose.yml
# services:
# api:
# image: my/api:1.0
# networks: [web, internal]
# environment:
# DATABASE_URL: postgres://postgres@db:5432/shop
# db:
# image: postgres:16
# networks: [internal]
# lb:
# image: nginx
# networks: [web]
# ports: ['80:80']
# networks:
# web: {}
# internal:
# internal: true
# 7) DO NOT use legacy --link any more
# docker run --link db:database ... # deprecated; only works on the default bridge
# It populates env vars (DB_PORT_5432_TCP=...) and /etc/hosts entries that go stale.
# 8) External DNS records inside a container
# Add --dns 1.1.1.1 --dns 8.8.8.8 if your hosts resolv.conf is unusable.
docker run --rm --dns 1.1.1.1 alpine nslookup example.com
Why it matters
Default to a user-defined bridge network for any project with more than one container. Container name = DNS name is the whole feature, and it removes a class of bugs (link order, restart races) that legacy --link papered over only some of the time.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Inside a network, containers reach each other by name. # From api: connect to host 'db'.Try it Yourself »
Discussion
Loading…