Resolving DNS failures in Compose networks

The most common Compose-in-DevContainer failure is an app that can’t resolve db or redis by name, even though both containers are running. The cause is almost always that the services aren’t sharing a user-defined network, so Docker’s embedded DNS resolver never gets involved. This page diagnoses and fixes service-name resolution in a Compose stack. It extends the Debugging Network & DNS Issues in Containers cluster.

Prerequisites

  • A Compose-backed DevContainer (dockerComposeFile + service)
  • dnsutils/iproute2 available in the app container for diagnosis
  • Docker Engine 24+ with Compose v2

How-To Steps

  1. Reproduce the failure precisely — resolution, not just connectivity:

    devcontainer exec --workspace-folder . getent hosts db || echo "name does not resolve"
    
  2. Confirm the embedded resolver is present. On a user-defined network, /etc/resolv.conf points at 127.0.0.11:

    devcontainer exec --workspace-folder . cat /etc/resolv.conf | grep 127.0.0.11 \
      || echo "not on a user-defined network"
    
  3. Put every service on one explicit network so names resolve:

    services:
      app:
        build: .
        command: sleep infinity
        networks: [devnet]
      db:
        image: postgres:16-alpine@sha256:1f3d...
        networks: [devnet]
      redis:
        image: redis:7-alpine
        networks: [devnet]
    networks:
      devnet:
        driver: bridge
    
  4. Recreate the stack so the network change takes effect, then verify resolution:

    devcontainer up --workspace-folder . --remove-existing-container
    devcontainer exec --workspace-folder . getent hosts db redis   # both resolve to container IPs
    
  5. Add a host alias only if a service must be reachable under a second name:

    services:
      db:
        networks:
          devnet:
            aliases: [database, primary-db]
    

Common Pitfalls

SymptomRoot CauseRemediation
db does not resolveServices on the default bridgeAttach all services to one user-defined network
Resolves after manual restart onlyNetwork change not appliedRecreate the stack with --remove-existing-container
Resolves to wrong containerDuplicate service alias across networksKeep one alias per name on the shared network
Public DNS works, service names don’tEmbedded resolver bypassedConfirm 127.0.0.11 is in resolv.conf

Conclusion

The essential invariant: Docker only resolves service names for containers on the same user-defined network. Declare one network, attach every service to it, and recreate the stack — service-name DNS then works deterministically, with no hardcoded IPs.

FAQ

Why does it work without a network block in a standalone docker compose up? Compose creates a default project network automatically there. In a DevContainer the wiring can differ, so declaring an explicit network removes the ambiguity.

Can I just use container IPs instead? No — container IPs change on every recreate. Service-name resolution on a shared network is the only stable approach.