Adopt the glossary's vocabulary in the mutable design docs
"control plane" -> controller and "substrate" -> foundation throughout 03-DESIGN, 00-META and the README, with 06-the-control-plane.md and 07-the-substrate.md renamed to 06-the-controller.md and 07-the-foundation.md. The immutable 02-DECISIONS records keep their original wording (and links to them are unchanged) — a term retired here may still appear there, which the glossary explains how to read. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
@@ -21,25 +21,25 @@ decisions:
|
||||
|
||||
# Connectivity
|
||||
|
||||
One of [the control plane's](06-the-control-plane.md) ten contexts, and the one with the most
|
||||
One of [the controller's](06-the-controller.md) ten contexts, and the one with the most
|
||||
moving parts: **overlay, resolution, exposure, filtering, certificates.**
|
||||
|
||||
It is written as a whole because the five are one design. They share inputs, they must agree, and
|
||||
every one of them today is computed in a different place by a different module from a different
|
||||
copy of the same facts.
|
||||
|
||||
## Why it is control-plane work
|
||||
## Why it is controller work
|
||||
|
||||
Apply [the test](06-the-control-plane.md) — *everything that needs to know about more than one
|
||||
Apply [the test](06-the-controller.md) — *everything that needs to know about more than one
|
||||
node* — to each responsibility:
|
||||
|
||||
| | needs to know | whose |
|
||||
|---|---|---|
|
||||
| **overlay** — who peers with whom, at what address | **every node**, and which of them can be dialled | control plane |
|
||||
| **resolution** — which name is which node | **every node** | control plane |
|
||||
| **exposure** — which public name reaches which container | **which node is publicly reachable** ([ADR 0007](../../02-DECISIONS/0007-connectivity.md)) | control plane |
|
||||
| **filtering** — which port is open, to whom | what is assigned here, and the overlay's shape | control plane decides, host applies |
|
||||
| **certificates** — who may present which name | which name belongs to which node | control plane |
|
||||
| **overlay** — who peers with whom, at what address | **every node**, and which of them can be dialled | controller |
|
||||
| **resolution** — which name is which node | **every node** | controller |
|
||||
| **exposure** — which public name reaches which container | **which node is publicly reachable** ([ADR 0007](../../02-DECISIONS/0007-connectivity.md)) | controller |
|
||||
| **filtering** — which port is open, to whom | what is assigned here, and the overlay's shape | controller decides, host applies |
|
||||
| **certificates** — who may present which name | which name belongs to which node | controller |
|
||||
|
||||
**Not one of the five can be answered by a machine on its own.** That is the whole reason this is
|
||||
a context rather than a set of node-local modules — and it is exactly what the current
|
||||
@@ -57,7 +57,7 @@ exist; WireGuard, the resolver and the proxy are all *a container or a package,
|
||||
|
||||
It is also what removes the last two upward dependencies.
|
||||
[Research 006](../../01-RESEARCH/006-mesh-from-scratch/host-size.md) counted exactly two modules
|
||||
opening a direct connection to the control plane's database — `wireguard` and `traefik` — and
|
||||
opening a direct connection to the controller's database — `wireguard` and `traefik` — and
|
||||
they are the reason every node permanently holds a credential to it
|
||||
([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)). Both are connectivity
|
||||
modules. **Closing this context closes that set.**
|
||||
@@ -74,7 +74,7 @@ wanted the exception.
|
||||
|
||||
**What made it look unavoidable:** a peer list cannot be written in a manifest. It is derived from
|
||||
every other machine, so it differs on each one and changes when any of them changes. So the
|
||||
manifest says its resources are **computed** — it names something in the control plane that works
|
||||
manifest says its resources are **computed** — it names something in the controller that works
|
||||
them out per node — and it is a module in every other respect: assigned, resolved, configured by
|
||||
settings, and absent from a machine nobody gave it to.
|
||||
|
||||
@@ -108,7 +108,7 @@ claim, and the collision is refused by name.
|
||||
**And the proxy's half, which was the other module reaching into the database.** A web application
|
||||
requiring a reverse proxy has to say *which name, which port*, and there was nowhere to put it —
|
||||
`requires` says a thing must exist and never said what to do with it. A module now contributes to
|
||||
a requirement, the control plane collects every contribution on a node, and the provider is given
|
||||
a requirement, the controller collects every contribution on a node, and the provider is given
|
||||
them as a file at a path it named. It reloads when that file changes, by the same `restart-on` the
|
||||
private network needed when a peer list changed under a running interface.
|
||||
|
||||
@@ -177,7 +177,7 @@ which of those it may dial, and which must dial it.
|
||||
**Keys.** Each node generates its own keypair. **The private key never leaves the machine**; the
|
||||
public key is published to the mesh. This is already true and it is already right — it is
|
||||
[ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)'s *a node holds its own
|
||||
identity* applied to the overlay, and it means the control plane computes a graph it cannot
|
||||
identity* applied to the overlay, and it means the controller computes a graph it cannot
|
||||
itself impersonate.
|
||||
|
||||
**Shape: a hub, with direct peering between co-located nodes.**
|
||||
@@ -217,7 +217,7 @@ files were right, the services were up, and every node reported success.
|
||||
document's own warning, arriving in its implementation: *a more specific route to a dead
|
||||
endpoint blackholes; it does not fall back to the general one.*
|
||||
- **The container runtime closes the door the overlay needs.** Docker sets the FORWARD policy to
|
||||
DROP, so a hub with `ip_forward` enabled still carries nothing between its spokes. The substrate
|
||||
DROP, so a hub with `ip_forward` enabled still carries nothing between its spokes. The foundation
|
||||
at tier 1 silently breaks the network at tier 2, and nothing in either tier's state says so. The
|
||||
hub inserts its own rule above those chains and removes it on the way down.
|
||||
|
||||
@@ -287,7 +287,7 @@ 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.
|
||||
language. Swapping dnsmasq for unbound changes that module and nothing in the controller.
|
||||
|
||||
**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
|
||||
@@ -377,7 +377,7 @@ vocabulary — the mirror of a database grant, where the consumer supplies a tar
|
||||
name rather than supplying nothing and receiving credentials.
|
||||
|
||||
**A workload on an unreachable node is proxied by a reachable one, across the overlay.** Which is
|
||||
the case is a mesh-level fact, which is the fourth reason exposure is control-plane work.
|
||||
the case is a mesh-level fact, which is the fourth reason exposure is controller work.
|
||||
|
||||
### What was built
|
||||
|
||||
@@ -482,7 +482,7 @@ something:
|
||||
|
||||
| | why not |
|
||||
|---|---|
|
||||
| decide what the machine **forwards** | the container runtime writes its own forwarding rules and a second policy is consulted alongside them, so a drop here stops every container on the node — the control plane included. Nothing in a manifest says what a machine routes, so there is nothing to derive it from either |
|
||||
| decide what the machine **forwards** | the container runtime writes its own forwarding rules and a second policy is consulted alongside them, so a drop here stops every container on the node — the controller included. Nothing in a manifest says what a machine routes, so there is nothing to derive it from either |
|
||||
| **flush the ruleset** when loading | that empties every table on the machine, the runtime's among them. Only the mesh's own table is replaced, and it is declared empty first so the replacement works on a machine loading one for the first time |
|
||||
| carry a **command to load itself** | the link may not carry an action ([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)). A service is declared to reflect the file instead, so replacing it restarts what loads it — the shape that rule leaves, used here for the first time for its real purpose |
|
||||
|
||||
@@ -549,7 +549,7 @@ defaults to the public authority's *production* endpoint. Two consequences, and
|
||||
worse than the lab problem that found it — every certificate experiment on a real node consumes
|
||||
production issuance quota, and a retry loop can exhaust it for a week.
|
||||
|
||||
**The mesh CA is not a bootstrap concern.** A joining node verifies the control plane against the
|
||||
**The mesh CA is not a bootstrap concern.** A joining node verifies the controller against the
|
||||
fingerprint in its token ([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)),
|
||||
so nothing needs the CA before membership. It certifies internal names afterwards, and that is
|
||||
all it does.
|
||||
|
||||
Reference in New Issue
Block a user