Skip to content

Use Apple container's built-in DNS for inter-container resolution when domain is registered #81

@Cyb3rDudu

Description

@Cyb3rDudu

Today, services in the same compose project can't resolve each other by name — getent hosts db from inside app returns nothing, so configs that use DB_HOST: db (the docker-compose default) just don't work. Users have to pin IPs into env vars or manually script extra_hosts.

Apple container already ships a DNS server that the daemon's bridge gateway answers on, for any domain registered via container system dns create <domain>. So we can register a domain per project, run containers with dotted names like db.<domain>, and get real DNS for free:

  • Container is named <service>.<domain> (Apple's convention from How to set which system dns to use for container apple/container#800)
  • --dns-domain <domain> is passed to container run, which writes nameserver <gateway> + domain <domain> into the container's /etc/resolv.conf
  • Both db (short, via the implicit search list) and db.<domain> (FQDN) resolve through the daemon's DNS server

In ComposeUp.run() it's just: derive a DNS label from projectName (lowercased, [a-z0-9-], ≤63 chars), shell out to container system dns list to check whether it's registered, and use the path above when it is. When it isn't, current behavior is unchanged plus a one-time printed note pointing at sudo container system dns create <domain>.

Tested with apple/container 0.12.3 on macOS 26. Two alpine containers db.testdomain and app.testdomain started with --dns-domain testdomain. From inside app:

/etc/resolv.conf:
    nameserver 192.168.65.1
    domain testdomain

getent hosts db.testdomain   → 192.168.65.62
getent hosts db              → 192.168.65.62

No /etc/hosts mutation, no per-container exec, survives container restarts (daemon updates the registration when IPs change).

The catch: sudo container system dns create <domain> is one-time per project and requires admin. For users who refuse sudo, behavior is unchanged.

I have a working implementation if you want it — ~70 net lines in ComposeUp.swift, a small sanitizer helper, ~15 unit tests, and one dynamic test that auto-skips if no domain is pre-registered. Happy to send a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions