Two things were treated as one. The mesh's own artifact store holds the store seat and is internal by design — reached by name over the overlay, no accounts, ADR 0082. Serving a registry publicly is a service the mesh can host: a module with its own name, accounts and storage, like anything else it runs for somebody. The conversion this report was written beside gave the seat holder a second public door over the same filesystem, which is neither. Keeps the original issue whole — no garbage collection, and the settings a routine needs are not enabled — drops the two-door complication, and sharpens one thing: deletion on the only door is deletion on a door with no accounts, which the predecessor kept behind its authenticated one.
78 lines
4.4 KiB
Markdown
78 lines
4.4 KiB
Markdown
---
|
|
status: open
|
|
opened: 2026-09-23
|
|
located-in: []
|
|
fixed-by:
|
|
amended-design:
|
|
---
|
|
|
|
# 108 — The registry has no garbage collection, and two doors make it harder to add
|
|
|
|
## 2026-09-26 — the second door was attached to the wrong thing
|
|
|
|
*Left in the title and in the text below rather than rewritten, because the reasoning that assumed
|
|
two doors is what a reader needs to see retracted.*
|
|
|
|
Two separate things were treated as one. **The mesh's own artifact store holds the store seat**: it
|
|
is internal, reached by name over the overlay, with no accounts, because being on that network is the
|
|
permission ([ADR 0082](../../02-DECISIONS/0082-the-registry-is-reached-by-name-and-trusted-by-the-overlay.md)).
|
|
**Serving a registry publicly is a service the mesh can host** — a module with its own name, its own
|
|
accounts and its own storage, like any other thing it runs for somebody. The conversion this report
|
|
was written beside gave the seat-holding store a second, public, authenticated door over the same
|
|
filesystem, which is neither of those: it is the internal store with an external face.
|
|
|
|
That second door is not being built. A publicly served registry, if one is wanted, is a module beside
|
|
the store rather than another way in to it, and it brings its own storage with it.
|
|
|
|
What that leaves here:
|
|
|
|
- **The complication in the title is gone.** One door means one registry process on the store's
|
|
filesystem, so the shared blob-descriptor cache and the deletion-cached-by-the-other-door problem
|
|
this report worried about do not arise at all.
|
|
- **The original issue is untouched, and is the whole of it.** The mesh's registry has no garbage
|
|
collection, never had, and the settings a collection routine depends on are not enabled.
|
|
- **One thing is sharpened rather than removed.** Enabling deletion on the only door enables it on a
|
|
door with no accounts, reachable by everything on the overlay. The predecessor kept deletion behind
|
|
its authenticated door — which it could, having one. So adding garbage collection now includes
|
|
deciding whether deletion is exposed on that door at all, or only ever performed by a routine the
|
|
mesh runs against its own store.
|
|
|
|
## What was observed
|
|
|
|
Reviewing the conversion that gives the mesh's image registry its public, authenticated name,
|
|
2026-09-23. The predecessor's registry module ran a maintenance routine on a timer: stop the
|
|
registry, `garbage-collect --delete-untagged`, restart, with a tag-retention step in front. The
|
|
mesh's registry has no such routine — it never did — and the conversion carried the settings the
|
|
routine depends on but not the routine.
|
|
|
|
The conversion also settled the public door as a **second registry process** on the same
|
|
filesystem, because the store's own door must stay account-free inside the mesh
|
|
([ADR 0082](../../02-DECISIONS/0082-the-registry-is-reached-by-name-and-trusted-by-the-overlay.md)).
|
|
The registry's garbage collector requires every writer stopped while it runs. There are now two.
|
|
Nothing in the mesh's vocabulary says *stop these two containers, run a one-shot against their
|
|
shared volume, start them again*; a `run-once` step runs beside containers, not instead of them.
|
|
|
|
Meanwhile the merged store holds 53 repositories and every build the mesh will ever make pushes
|
|
another layer set into it. Disk grows without bound.
|
|
|
|
## Why it matters beyond this instance
|
|
|
|
A registry without garbage collection is a slow leak that presents as a full disk on a node that
|
|
serves everything else. The predecessor knew this and scheduled for it; the mesh forgot it in the
|
|
conversion because the routine was a script beside the module, not a resource in it — the shape
|
|
[issue 098](../098-taking-a-module-replaces-a-configuration-nobody-compared/00-report.md) describes
|
|
for configuration, here for behaviour.
|
|
|
|
It also asks something of the module system: a maintenance window over several containers is a
|
|
real thing services need, and the mesh cannot express one.
|
|
|
|
## Open questions
|
|
|
|
- Should the module system gain a maintenance step — a one-shot that quiesces named containers,
|
|
runs, and restores them — or is this better solved by a registry that does not need its writers
|
|
stopped (a storage backend the mesh does not run today)?
|
|
- Tag retention before GC: the predecessor kept the last N tags per repository; the mesh names
|
|
images by digest and moves by version — is retention "the digests no recorded build names"?
|
|
- Who owns the routine when the store and its public door are two modules — the store, since the
|
|
volume is its?
|