What a module may borrow, what it may need, and what one assignment gets
Three additions, all written by trying to write a real database module and finding out what could not be said. A module may mirror an image it did not write. Naming an upstream reference directly needs every machine to reach a public registry and pins to a tag somebody else can move. A module may need a secret of its own — a superuser password is not FOR anybody, so the mechanism that hands credentials to consumers cannot express it. Per node, so three machines have three passwords. And the provisioner watches, which is what lets it be a module rather than a binary somebody places. It polls rather than watching the filesystem, because the host writes atomically and a watch on a replaced path silently stops working. One assignment now gets a working database provider: two directories, two pinned containers, a sealed password and the grants manifest.
This commit is contained in:
@@ -133,6 +133,65 @@ answered to the asker and kept nowhere.
|
||||
- **Nothing is published until everything is built.** Half a module in the store, under a digest
|
||||
the mesh never records, is reachable, unreferenced, and indistinguishable from something in use.
|
||||
|
||||
## What a module may build, and what it may only borrow
|
||||
|
||||
| kind | is |
|
||||
|---|---|
|
||||
| **image** | built from a Dockerfile in this repository |
|
||||
| **archive** | a directory in this repository, packed |
|
||||
| **upstream** | an image somebody else built, mirrored into the mesh's own registry |
|
||||
|
||||
**The third exists because a module usually runs software it did not write.** A database module
|
||||
ships configuration and a provisioner and does not build a database. Naming the upstream reference
|
||||
directly would need every machine to reach a public registry, and would pin to a tag its owner can
|
||||
move — which is what pinning exists to prevent
|
||||
([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)). Mirroring is what the
|
||||
bootstrap already does by hand; this makes it something a module can say.
|
||||
|
||||
An upstream reference with **no tag or digest is refused**: what gets mirrored would be whatever
|
||||
`latest` means today, and a module pinned to that is not pinned.
|
||||
|
||||
## A module's own secret
|
||||
|
||||
A database has a superuser password, a broker an administrator, a registry an account. **None of
|
||||
them is *for* anybody** — they are not the credential a consumer is given, and the mechanism that
|
||||
hands those out has a consumer in the middle of it.
|
||||
|
||||
So a module says what it needs and where to put it, and the mesh generates one **per node**,
|
||||
seals it to that machine and reads it no more than it reads any other secret. Per node
|
||||
deliberately: a module running on three machines has three passwords, where one in the manifest
|
||||
would put the same secret on every machine that ever runs it, in a file anybody can read, for ever.
|
||||
|
||||
Made once and kept, or a running database would be handed a password it was not started with.
|
||||
Remade when the machine's sealing key changes. **Declared and not made is refused**, because a
|
||||
module whose own credential is silently absent starts, fails to authenticate, and the reason is
|
||||
three layers from the machine reporting it.
|
||||
|
||||
## What one assignment gets you
|
||||
|
||||
A database module, written to see whether it could be:
|
||||
|
||||
```
|
||||
directory /var/lib/mesh/postgres
|
||||
directory /var/lib/mesh/postgres/grants
|
||||
container the database pinned by digest, mirrored
|
||||
container the provisioner pinned by digest, mirrored
|
||||
file the superuser password sealed to this machine
|
||||
file what its consumers asked for
|
||||
```
|
||||
|
||||
**The provisioner watches** rather than being invoked. That is what lets it be a module: run once,
|
||||
it needs something to run it after every declaration — a timer, or a unit wired to a file.
|
||||
Watching, it is an ordinary long-running service the host already supervises. It polls rather than
|
||||
watching the filesystem, because the host writes atomically: the file is replaced, so a watch on
|
||||
the path stops seeing anything after the first replacement, and a watcher that silently stops
|
||||
working is worse than a poll.
|
||||
|
||||
Writing it found one thing wrong, and it was the manifest rather than the host: a container
|
||||
declared `restart-on`, which is a service field, and the host refused it by name. **It is right
|
||||
to.** A container whose own definition changes is recreated, and a file it mounts is read by the
|
||||
process inside, which is that image's business.
|
||||
|
||||
## Where artifacts go
|
||||
|
||||
**The registry the bootstrap already pulls from**, for both images and archives. An OCI registry
|
||||
|
||||
Reference in New Issue
Block a user