Repository navigation
[Request]: First-class container-to-container DNS discovery on custom networks #1809
Description
Activity
Update: I opened a draft implementation PR for the container-facing DNS part:
What it covers:
- containers can query their vmnet gateway on UDP port 53
- responses are scoped to source IPs inside active container networks
- bare container hostnames resolve through the existing network service
- external names are forwarded to upstream DNS servers so the listener does not break normal container DNS
The PR is intentionally draft/RFC because it binds wildcard UDP 53 and currently discovers upstreams from
/etc/resolv.conf; both are design choices that should get maintainer review.It is stacked on #1810 because the DNS path needs the hostname normalization/trailing-dot behavior from that PR.
Remaining work for Compose-style parity: explicit network aliases/service aliases still need API/CLI support after the bare-hostname DNS path is settled.
Follow-up draft PR for explicit aliases is open:
This stacks on #1813 and adds a narrow alias registration path:
AttachmentOptions/Attachmentcarryaliases--network backend,alias=db,alias=databaseparses repeated aliases- network allocation registers aliases as additional DNS names for the same address
- releasing the attachment removes the primary hostname and aliases together
- container creation checks aliases for duplicate-name conflicts
I could not complete live alias validation because the local debug apiserver launch did not become healthy during the smoke-test attempt. Unit/build coverage is included in the PR body, and the installed
/usr/localservice was restored afterward.Status update:
- Add DNS forwarding groundwork #1813 is now marked ready for review. It includes the container-facing DNS listener, standard DNS query validation, source-network scoping, upstream forwarding, and invalid/loopback upstream filtering.
- Add network attachment aliases #1815 has been rebased on top of the updated Add DNS forwarding groundwork #1813 stack and now includes additional coverage for alias serialization compatibility and client attachment-option plumbing.
- Add network attachment aliases #1815 remains draft because live alias smoke validation is still blocked by the local debug apiserver launch issue described in the PR body. The in-process parser/allocator/resource/client coverage passes, and the installed
/usr/localrelease service was restored after the smoke attempt.
Status update: #1815 is now ready for review.
I was able to complete live alias validation by staging the debug build into a temporary install root and starting the service with explicit
--install-root/--log-rootsettings.Validated behavior:
container run --network codex-alias-live,alias=db,alias=database ...registers both aliases- peer containers on the same network resolve
db,database, and the primary container name through the network gateway DNS - a duplicate
alias=dbattachment fails with the expected duplicate-hostname error - test containers/networks were removed afterward
- the installed
/usr/localrelease service was restored and verified healthy
FQDN-based service discovery is one of the biggest differences from Docker Compose networking. In our testing:
- Container name → FQDN pattern:
<container-name>.containers.local - This only works within the same container network
- Cross-network (multi-compose-file) service discovery doesn't work yet
We documented the FQDN patterns, working examples, and the cross-network workaround (manual host mapping) at maccontainer.dev/installation/ — the troubleshooting section covers this exact DNS issue.
It's not Docker's DNS-based service discovery, but the FQDN pattern is predictable once you know the naming convention.
- Container name → FQDN pattern:
Thanks, that matches the same-network constraint I’ve been seeing. I think the useful invariant is “container ID/name + configured DNS domain” rather than a Docker-style per-network service-name registry; depending on local DNS config that can show up as
<container>.containers.local,dev.internal, or another configured domain.For Compose parity, the remaining gap is still bare service names and aliases (
db,database) on the service network, because Compose files generally do not want to depend on the full generated container FQDN. That is what #1815 is trying to cover narrowly: register aliases on the same network attachment and keep duplicate-name checks scoped there.I agree cross-network / multi-compose-file discovery is a separate problem and should stay out of this first pass.
Reacted by DavisWe needed exactly this for compose-shaped workflows on container 1.2.0, so here is what we measured and what we ended up building, in case either is useful.
First, port data that complements the #1813 design note. The gateway binds there failed with EADDRNOTAVAIL from the helper. From plain user space, with a container running and the bridge up so the gateway address exists, the failure is different and harder:
bind 192.168.64.1:53 -> EPERM (with and without SO_REUSEADDR) bind 127.0.0.1:80 -> EPERM bind 0.0.0.0:53 -> EADDRINUSE bind 192.168.64.1:2053 -> okEvery port below 1024 is EPERM for an unprivileged process on current macOS, both TCP and UDP, on every address we tried. So a container-facing listener on 53 cannot exist host-side for a non-root engine at all. resolv.conf cannot carry a port, which rules out the unprivileged ports that do bind. The only place a :53 listener can live is inside the guest, which is vminitd territory rather than the engine's.
What we built instead needs no listener. When a container joins a network, the runtime asks the network helper for everything already attached (one new XPC route that returns the current attachments) and writes each peer into the joining guest's /etc/hosts, bare and qualified:
192.168.64.2 dnsweb dnsweb.container.internalThe guest's resolv.conf also gets
search container.internalwhen no domain was configured. Since getaddrinfo consults hosts before DNS, service names resolve inside the containers with no resolver in the path and no root anywhere. Verified by starting nginx asdnsweb, then a second container, and fetchinghttp://dnsweb/andhttp://dnsweb.container.internal/from it.The limitation is honest: hosts files are written at boot, so a container does not learn about peers that start after it. A stack brought up in dependency order, which is what compose does, sees every name it needs. Aliases from #1815 would slot into the same hosts entries.
The patch is small (allocator enumeration, the XPC route, client call, hosts composition in the runtime, about 150 lines). Glad to open a PR if the maintainers want it as an interim step while the DNS listener work in #1813 evolves.
- Thanks—this is very useful. The bind results complement the helper-side EADDRNOTAVAIL findings in #1813, and the /etc/hosts prototype provides a concrete interim fallback with a clearly stated limitation. I can’t speak for the maintainers on whether they’d want that approach upstream, but if you’re willing, opening it as a draft PR and linking it here would make the implementation and trade-offs easier to evaluate alongside #1813’s DNS groundwork and #1815’s alias plumbing. Tests covering same-network scoping, preservation of existing hosts entries, and the late-join/non-refresh case would be especially helpful. Thanks for measuring and prototyping this.
Hi @thromel, I asked deepseek-v4-flash-0731 to build a customized vminitd image as described in this doc that attachs some eBPF which will redirect any traffic to a loopback address (hardcoded to 127.0.8.6 for now) at port 53 to a real dns server (defaults to 1.1.1.1:53, but can be set to any other {ip}:{port}). I'm new to both eBPF (where the code looks simple enough and reasonable to me) and vminitd (where the code
I didn't even try to readwas migrated to aya and much more readable), but it does work as expected. Hopefully this is somewhat useful or at least interesting for the container-facing DNS work. You could try it with
container run -it --rm --init-image ghcr.io/l-hedgehog/aa-tils/vminitd-ebpf-dns:0.45.0 --kernel-arg dnslink.gateway={ip} --kernel-arg dnslink.port={port} --dns 127.0.8.6 {image}.- added a commit that references this issue
on Sep 14, 2026 A downstream data point, since this one is the single biggest compose-compatibility gap I have hit.
I maintain compose, a
container composeplugin, and Orchard. Because hostnames have to be unique across every container on the machine, a service declared asdbhas to be brought up asmyapp-db. That is fine for the container list, and fatal for compose compatibility: essentially every compose file in the wild haspostgres://db:5432orredis://cachehard-coded into an environment variable, because on Docker the service name resolves on the project network.So the practical cost of this issue is not "nice DNS ergonomics", it is that compose files cannot be moved across unedited, which is the entire reason people want compose here. Per-network name scoping, as described above, would fix it outright. Happy to test against real projects if that is useful to whoever picks it up.
Reacted by Gilles De Mey and peterkelm
Feature or enhancement request details
Please add first-class container-to-container DNS discovery for containers attached to the same
containernetwork, including bare container names and network aliases.This came up while testing Compose-compatible workflows with
container-compose. Compose users expect service names such asweb,db, and network aliases to resolve from peer containers on the same network without a global host DNS setup step.Related tracking:
Current behavior on
container1.0.0:The peer container receives the network gateway as its resolver:
The container is reachable by IP from the same network, but name lookup returns NXDOMAIN:
The currently documented workaround appears to be configuring a DNS domain with
container system dns create <domain>plus settingdns.domain. That can make FQDN/search-domain flows work, but it is not the same as network-scoped, Compose-style service discovery. It also requires global host DNS configuration for what is usually expected to be a per-network container runtime feature.A useful end state would be one of these:
web-> that container's network IP.Environment used for the repro:
I agree to follow this project's Code of Conduct.