Group 2 is resolved: containers resolve, nothing is copied, a route's name says where it arrives
Issue 110's cause was not the filter: the runtime had never been told, and the resolver dropped a query arriving on a bridge. ADR 0148 step 3 landed once it did (109, 151 resolved). ADR 0151 composes a route's internal name under the serving node and drops the suffixed alias (139, 157 resolved). Design 08 amended; a fact in 0148 corrected.
This commit is contained in:
@@ -103,6 +103,13 @@ reintroduces 109 and 135 — silently, and on a live mesh, which is exactly how
|
||||
([issue 110](../04-ISSUES/110-a-container-on-the-runtimes-own-network-cannot-reach-the-resolver/00-report.md));
|
||||
and on two of four machines the resolver binds loopback only, so the runtime hands containers a
|
||||
public resolver instead. Both are prerequisites, not related work.
|
||||
|
||||
> **Progressive insight — 2026-09-30, later the same day. The loopback claim was wrong.** The
|
||||
> resolver bound the private address on all four machines; on two the runtime had never been told
|
||||
> to use it, and on all four the resolver discarded a query that arrived on the runtime's bridge.
|
||||
> The step stands; the facts under it were those. Both fixed the same day
|
||||
> ([issue 110's resolution](../04-ISSUES/110-a-container-on-the-runtimes-own-network-cannot-reach-the-resolver/01-resolution.md)),
|
||||
> and step 3 landed after them.
|
||||
2. **The runtime is told which resolver to use, per machine, as a file** — not per container as a
|
||||
creation-time argument, or the resolver's address is back in every container's identity and the
|
||||
problem has only got smaller.
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
topic: the tiers
|
||||
status: accepted
|
||||
date: 2026-09-30
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0066-public-routing-is-name-agnostic.md
|
||||
---
|
||||
|
||||
# 151. A route's internal name is composed under the node that serves it
|
||||
|
||||
## Context
|
||||
|
||||
A module that requires a route is given two names from one label: a public one, `<label>.<public
|
||||
domain>`, and an internal one, `<label>.<node>.internal`
|
||||
([ADR 0138](0138-an-assignment-binds-an-endpoint-and-says-how-far-it-reaches.md)). Both were composed
|
||||
from the node the module runs on.
|
||||
|
||||
The two are answered differently. The public name is published into every machine's roster at the
|
||||
address of the node whose proxy serves it ([ADR 0066](0066-public-routing-is-name-agnostic.md)), so
|
||||
it reaches the proxy from anywhere in the mesh. The internal name is answered by every machine's
|
||||
resolver as *anything under a node's name goes to that node*
|
||||
([design 08 §2](../03-DESIGN/01-to-be/08-connectivity.md)) — the node it was composed from, which is
|
||||
the consumer's. Where the proxy runs on another machine, that name sends a client to a machine with
|
||||
nothing listening, while the public name works
|
||||
([issue 139](../04-ISSUES/139-an-internal-route-name-resolves-to-the-consumers-node/00-report.md)).
|
||||
Every route on this mesh today is served beside its module, so it has not been seen; `route` is
|
||||
provided mesh-wide precisely so that stops being true.
|
||||
|
||||
Beside it, the roster gave every routed name a second entry with the mesh's suffix appended —
|
||||
`<name>.<public domain>.internal` — because it composed a full name for every entry as it does for a
|
||||
machine. That name resolved on every machine, was served by nothing, and was refused by the proxy at
|
||||
the handshake; the first three names tried while reproducing an unrelated issue were those, and the
|
||||
evidence pointed at a regression that had not happened
|
||||
([issue 157](../04-ISSUES/157-a-routed-names-internal-alias-is-served-by-nothing/00-report.md)).
|
||||
|
||||
## Considered Options
|
||||
|
||||
**1. Keep the consumer's name and publish it at the serving node's address**, as the public name is.
|
||||
The name stays `<label>.<consumer>.internal` and an exact roster entry overrides the wildcard.
|
||||
Rejected: it makes `<x>.<node>.internal` mean *goes to that node* except when it does not, which is
|
||||
the one rule the resolver design states; it needs an entry per route where the wildcard needed none;
|
||||
and which of an exact entry and a wildcard a resolver answers first is the resolver's business, which
|
||||
the mesh deliberately does not know.
|
||||
|
||||
**2. A proxy on every machine, so the serving node is always the consumer's.** Rejected for this
|
||||
question: it is a different decision about what `route` is — a node-scoped seat with a mesh-wide
|
||||
fallback — and this mesh runs one proxy on the hub today. Whatever is decided there, a route served
|
||||
from another machine must have a name that reaches it.
|
||||
|
||||
**3. Compose the internal name under the node that serves the route.** Chosen.
|
||||
|
||||
## Decision
|
||||
|
||||
**A route's internal name is `<label>.<serving node>.internal` — composed under the node whose proxy
|
||||
answers the route, which is the machine the request arrives at.** The public name is unchanged:
|
||||
`<label>.<public domain>` of the node the module runs on, which is where the operator put it.
|
||||
|
||||
Where the proxy runs beside the module — every route on this mesh today — the two nodes are one and
|
||||
nothing changes. Where it does not, the name says where the request goes, which is what a name under
|
||||
a node's name has always meant.
|
||||
|
||||
**A routed name has no mesh form.** The roster publishes it as itself, once, at the serving node's
|
||||
address. Only a machine has a bare name beside its full one.
|
||||
|
||||
What certifies the internal name is unchanged by this: the proxy that terminates it obtains a
|
||||
certificate from the mesh's authority for the names it is given, and it is given this one.
|
||||
|
||||
Taken on the operator's standing instruction to answer the open design questions in the work order.
|
||||
|
||||
## How this is checked
|
||||
|
||||
- **Composition.** A controller test contributes a route from a module on one node to a proxy offered
|
||||
from another, gathered the way the controller gathers a consumer's contribution for a provider on
|
||||
another machine, and asserts the internal name carries the serving node.
|
||||
- **Publication.** A controller test renders a roster with a machine and a routed name and asserts
|
||||
the routed name appears as itself, once, and never with the suffix appended.
|
||||
- **On the mesh.** After the change no machine's roster carries a `<domain>.internal` entry, and a
|
||||
route's internal name still answers from a container with a certificate from the mesh's authority.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **A route served from another machine now has a usable internal name.** The first module assigned
|
||||
that way will resolve, where before it would have resolved to the wrong machine with no error.
|
||||
- **The internal name of a route can change when its proxy moves.** A route re-homed from one proxy
|
||||
to another gets a new internal name, as the design's rule implies; clients that dialled the old one
|
||||
reach the old machine. The public name does not move with the proxy and is the stable one.
|
||||
- **The roster is one line shorter per routed name**, and a person reading a hosts file no longer
|
||||
finds names that resolve to a refusal.
|
||||
- **Issue 139's second question — a per-node route holder — is left open**, and is a decision about
|
||||
what a seat is rather than about a name.
|
||||
|
||||
## References
|
||||
|
||||
- [issue 139](../04-ISSUES/139-an-internal-route-name-resolves-to-the-consumers-node/00-report.md) — the question
|
||||
- [issue 157](../04-ISSUES/157-a-routed-names-internal-alias-is-served-by-nothing/00-report.md) — the alias
|
||||
- [ADR 0066](0066-public-routing-is-name-agnostic.md) — routed names propagate mesh-wide; extended here
|
||||
- [ADR 0138](0138-an-assignment-binds-an-endpoint-and-says-how-far-it-reaches.md) — how the two names are composed and how far each reaches
|
||||
- [design 08 §2](../03-DESIGN/01-to-be/08-connectivity.md) — anything under a node's name goes to that node
|
||||
@@ -200,6 +200,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0109** — [A package registry seat is one per ecosystem, not one for all of them](0109-a-package-registry-seat-is-one-per-ecosystem.md)
|
||||
- **0126** — [A module declares its own seats; the mesh reserves its own](0126-a-module-declares-its-own-seats.md)
|
||||
- **0148** — [The mesh's names are resolved, not copied into every container](0148-the-meshs-names-are-resolved-not-copied-into-containers.md)
|
||||
- **0151** — [A route's internal name is composed under the node that serves it](0151-a-routes-internal-name-is-composed-under-the-node-that-serves-it.md)
|
||||
|
||||
### What runs on them, and how it gets there
|
||||
|
||||
|
||||
Reference in New Issue
Block a user