Adetayo Akinsanya unkletayo.dev

User-Defined Networks and Embedded DNS Resolution in Docker

Understanding embedded DNS servers, service discovery by container name, and custom bridge isolation.

Adetayo Akinsanya (unkletayo) 2026-10-02

Part 14 in Series — Catch up on the previous article: Port Publishing Under the Hood: iptables DNAT, Userland Proxies, and Host Routing (Part 13) before diving into this post.

A backend engineering team deploys a web application consisting of a Node.js API service and a PostgreSQL database on a single server using default Docker flags:

docker run -d --name db-server postgres:15
docker run -d --name api-service my-node-api

In the API configuration file, the developer hardcodes the database connection string using the container’s IP address: postgres://172.17.0.2:5432/appdb.

During a routine host kernel update, the server reboots.

When the Docker daemon starts up, api-service initializes faster than db-server. The daemon assigns 172.17.0.2 to api-service and 172.17.0.3 to db-server.

The API server crashes continuously with ECONNREFUSED because container IP addresses are ephemeral and non-deterministic across restarts.

When the team creates a User-Defined Bridge Network:

docker network create app-net
docker run -d --name db-server --network app-net postgres:15
docker run -d --name api-service --network app-net my-node-api

The connection string becomes postgres://db-server:5432/appdb, and the service connects reliably across restarts.

How does Docker resolve container names like db-server into dynamic IP addresses without external DNS servers?


1. Why Default Bridge Networks Lack Automatic DNS

On the default bridge network (docker0), automatic DNS resolution by container name is disabled.

If container_A attempts to resolve container_B by name on the default bridge, the query fails:

# Inside container_A on default bridge:
ping container_B
ping: bad address 'container_B'

Legacy Docker installations relied on --link container_B, which injected static IP entries into the container’s /etc/hosts file at startup. However, --link is deprecated because /etc/hosts cannot update dynamically when target containers restart with new IP addresses.


2. User-Defined Bridge Networks

When you execute docker network create app-net, Docker creates a brand new, isolated virtual bridge interface (e.g., br-a1b2c3d4e5f6) in the host network namespace.

                              HOST NETWORK NAMESPACE
 +-------------------------------------------------------------------------+
 |  DEFAULT BRIDGE (docker0)            USER-DEFINED BRIDGE (br-a1b2c3d4)  |
 |  Subnet: 172.17.0.0/16              Subnet: 172.18.0.0/16              |
 |  No Container DNS Resolution         Embedded DNS Enabled!              |
 +-------------------------------------------------------------------------+
       |                                      |
       v                                      v
 [ Legacy Containers ]               [ Service: api-service ] <---> [ Service: db-server ]
                                     (Resolves "db-server" -> 172.18.0.3 via DNS!)

Key Advantages of User-Defined Networks:

  1. Automatic Service Discovery: Containers resolve each other automatically using container names or network aliases (http://db-server:5432).
  2. Network Isolation: Containers attached to app-net cannot communicate with containers on docker0 or other-net, preventing unauthorized cross-service snooping.
  3. Dynamic Attachment: You can connect or disconnect running containers from networks on the fly using docker network connect.

3. The Embedded DNS Server Engine (127.0.0.11)

How does Docker perform DNS lookups inside containers attached to user-defined networks?

When a container joins a user-defined network, Docker modifies the container’s /etc/resolv.conf file to point to a special loopback address:

# Inside container /etc/resolv.conf:
nameserver 127.0.0.11
options ndots:0

127.0.0.11 is the Docker Embedded DNS Server.

[ Application Code in Container ]
  |
  |  Sends DNS Query: "db-server"
  v
[ UDP 127.0.0.11:53 (Embedded DNS Proxy inside Container NetNS) ]
  |
  +--- Is query a container name in local network?
  |          |
  |          +---> YES: Resolves IP from Docker Daemon Internal Table (172.18.0.3)
  |          |
  |          +---> NO:  Forwards DNS query to Host's Upstream DNS (8.8.8.8)

Step-by-Step DNS Resolution Trace:

  1. Application code executes a database client connection request to host db-server.
  2. The OS C library issues a UDP DNS query for db-server on port 53.
  3. The query is intercepted by the local Embedded DNS Server listening on 127.0.0.11:53.
  4. The DNS engine checks Docker’s internal container name resolution table:
    • If db-server matches an active container attached to the same network, it returns 172.18.0.3 instantly.
    • If the query is an external internet domain (e.g., api.stripe.com), it forwards the request to the upstream DNS nameservers configured on the host host machine.

Default Bridge vs User-Defined Bridge Comparison

Feature / BehaviorDefault bridge (docker0)User-Defined Network (docker network create)
DNS Resolution by Name❌ Disabled (Fails unless using deprecated --link)Enabled automatically via 127.0.0.11
Network SubnetShared 172.17.0.0/16Dedicated isolated subnet (e.g., 172.18.0.0/16)
Cross-Container IsolationLow (All default containers share docker0)High (Strict network boundary isolation)
Hot-Plugging Interfaces❌ Requires container recreation✅ Supported (docker network connect/disconnect)
Custom IP Address RulesManaged automaticallySupports explicit --ip static assignment

Summary & Next Steps

User-Defined Networks provide reliable service discovery and security isolation for containerized architectures:

  • Ephemeral Container IPs make hardcoding IP addresses in application code brittle and prone to outages.
  • User-Defined Networks (docker network create) isolate microservice subnets and enable automatic container name resolution.
  • The Embedded DNS Server (127.0.0.11) intercepts UDP port 53 queries inside container network namespaces, resolving container names to dynamic IPs.

In the next article, we transition to Module 5 and explore Storage Drivers Deep Dive: OverlayFS Layering and Copy-On-Write (CoW) Performance Overhead.

References & Further Reading

  1. QEMU Project. QEMU User Space Emulation (qemu-user-static). QEMU Docs.
  2. Open Container Initiative. OCI Image Format Specification — Image Index and Manifest Lists. OCI Standard.
  3. Docker Inc. Leverage Multi-CPU Architecture Images with docker buildx. Docker Docs.

Up Next in Series →

Part 15: Storage Drivers Deep Dive: OverlayFS Layering and Copy-On-Write (CoW) Performance Overhead

Continue to Part 15 →