Record the resolver as built, and the two things it must not do

A service is reached at <service>.<node>.internal, so what resolves is anything
under a node's name. The mesh writes the data and runs no daemon; two roles,
two claims, because systemd-resolved cannot serve a wildcard at all.

Both prohibitions were found by a machine rather than by reasoning: an address
systemd already held, and reading resolv.conf for upstreams that now point at
itself.
This commit is contained in:
2026-08-31 14:23:02 +02:00
parent 6ecd03694b
commit f3ffdae909
+35
View File
@@ -277,6 +277,41 @@ joins, and a module that did not would be one whose containers cannot reach anyt
somebody starts by hand is not the mesh's to configure, and reaching into every container on a somebody starts by hand is not the mesh's to configure, and reaching into every container on a
machine — declared or not — is what a nameserver in `resolv.conf` would be for. machine — declared or not — is what a nameserver in `resolv.conf` would be for.
### The resolver, built
*2026-08-31.* **A service is reached at `<service>.<node>.internal`** — the first label is the
service, the rest is the node — so what resolves is *anything under a node's name*, going to that
node. What routes it once it arrives is a proxy's, and stays separate.
**The mesh writes the data and runs no daemon.** One wildcard per machine, from the same set that
writes the hosts file. A resolver is third-party software and runs *on* the mesh rather than being
*of* it: the mesh has no business shipping one, choosing which one, or knowing its configuration
language. Swapping dnsmasq for unbound changes that module and nothing in the control plane.
**Two roles, two claims, because they are different things.** systemd-resolved cannot answer a
wildcard at all — it routes the mesh's suffix to something that can. Treating serving and asking
as one role produces a module that cannot work.
| | claims | |
|---|---|---|
| serving | `the-dns-port` | answers the wildcards |
| asking | `the-resolver-configuration` | decides what the machine asks |
So *which* resolver is not a mesh-wide decision. One machine can use what systemd already owns and
another can run dnsmasq, and two of either on one machine is refused rather than fought over.
**Two things a resolver must not do**, both found by a machine rather than by reasoning:
- **Take an address something else holds.** systemd-resolved holds `127.0.0.53` *and* `127.0.0.54`.
- **Read `resolv.conf` for its upstreams.** Whatever points a machine at the mesh writes the
resolver's own address there, so it becomes its own upstream and every query it cannot answer
loops until its receive queue fills. It needs no upstream: only the mesh's suffix is routed to
it.
*Checked on two machines, through the path an application takes — nsswitch, files, then DNS —
because the module deciding what the machine asks is half of what is being tested and only that
path goes through it.*
**That is now the second reason to want a resolver**, and it is a different one from the trigger **That is now the second reason to want a resolver**, and it is a different one from the trigger
above: above: