Proposed for the operator's review: settings declared with defaults and cost (0164), container-runtime as a kernel capability (0165), node-container-runtime seat with the host creating containers through its holder (0166), and the runtime's file written by modules that are not its own (190).
152 lines
12 KiB
Markdown
152 lines
12 KiB
Markdown
---
|
|
topic: what runs on it
|
|
status: proposed
|
|
date: 2026-10-01
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 02-DECISIONS/0161-what-deserves-a-seat.md
|
|
---
|
|
|
|
# 166. The container runtime is a node seat, and the host creates containers through its holder
|
|
|
|
## Context
|
|
|
|
Every container the mesh runs on a machine is created by the host, which looks for a runtime
|
|
(`docker info`, then `podman info`) and drives that runtime's command line itself: run, inspect,
|
|
remove, exec. Research 012 called this "detected rather than declared": the host takes over whatever
|
|
runtime it finds. Nothing in the mesh owns the runtime. Its package came from the foundation bundle
|
|
or was already on the machine. Its configuration file was written by hand, differs on each of the
|
|
four machines, and is also written into by two modules that are not the runtime's
|
|
([issue 190](../04-ISSUES/190-the-runtimes-configuration-is-written-by-modules-that-are-not-the-runtime/00-report.md)).
|
|
Its service is declared by those same two.
|
|
|
|
The operator set the direction:
|
|
|
|
- a module for the runtime, on every machine, owning "what is needed to run containers here": its
|
|
packages, its configuration and its service;
|
|
- that module holds a node seat for the runtime, so a second runtime (podman) can later compete
|
|
for the seat;
|
|
- the host stops speaking to the runtime directly and uses the seat's holder. The host stays the one
|
|
that decides, and the holder becomes the one that executes;
|
|
- every container on the machine is in scope, not only the mesh's. A development environment started
|
|
by hand, or a test database a tool runs, is legitimate. The host already calls these *strays*: 3,
|
|
8 and 25 on three of the machines on the day of deciding;
|
|
- the runtime's events and verbs are subjects on the bus, and the mesh's own interface is built on
|
|
them. The third-party interface run until now was removed by hand.
|
|
|
|
[ADR 0161](0161-what-deserves-a-seat.md)'s test for a seat is whether the mesh's own code finds it by
|
|
name. Here it does: the host would look up the holder on its own machine. A singular role of a module
|
|
held once per machine is a `node-*` seat ([ADR 0121](0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md)),
|
|
in the controller's seed.
|
|
|
|
The constraint that decides most of this record is a cycle. The bus runs in containers. On the
|
|
broker's machine, the broker's own container is created by the host. A holder's code served from a
|
|
container cannot create the container that runs it. On a first machine, before the controller exists,
|
|
nothing holds anything.
|
|
|
|
## Considered Options
|
|
|
|
1. **The host calls the holder's verbs over the bus.** Rejected: with the broker down, no machine can
|
|
create any container, including the broker's. The mesh would be unable to restart its own
|
|
transport.
|
|
2. **The holder picks a dialect that the host speaks itself, as with the uplink.** Rejected: the
|
|
host would still drive the runtime, and the module would drive it too for every other caller.
|
|
That is two programs speaking to one daemon, and they come to disagree about the same machine
|
|
(the installer's preflight already exists to avoid this).
|
|
3. **The holder's code runs as a supervised process on the machine and serves the seat's verbs
|
|
twice: locally to the host, on the bus to everyone else.** Adopted.
|
|
|
|
## Decision
|
|
|
|
**`node-container-runtime` is a seat of the mesh's own, node-scoped,** in the controller's seed under
|
|
this record. It delivers no provision; what it carries is its role's protocol: verbs its holder must
|
|
serve ([ADR 0132](0132-a-seat-carries-the-tools-its-holder-must-serve.md)) and events its holder emits
|
|
([ADR 0129](0129-a-seat-carries-the-protocol-of-its-role.md)). The runtime's module, `docker`, claims
|
|
it and is assigned to every machine. A podman module may claim it later; one machine runs one.
|
|
|
|
**The seat's verbs cover every container on the machine:** list, inspect, logs, stats, start, stop,
|
|
restart, create and remove. A mesh-held container is marked by the host's label and says which
|
|
assignment holds it. **Creating or removing a mesh-held container is the host's alone.** Any other
|
|
caller is refused naming the assignment, because the host would undo it at its next apply. Starting,
|
|
stopping or restarting one is allowed, and the answer says the host will restore what its
|
|
declaration says. A container the mesh does not hold is the caller's to do anything with.
|
|
|
|
**The seat's events are the runtime's own** — a container created, started, stopped, died, removed,
|
|
its health changed. They are emitted on the seat's subjects, so every holder emits the same events and
|
|
no reader depends on which runtime holds the seat. As
|
|
[ADR 0160](0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md)
|
|
decides, the subjects are issued by the controller, not composed by the module.
|
|
|
|
**The holder's code is a supervised process, not a container** ([ADR 0150](0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md)).
|
|
A runtime cannot be run by the thing it runs. The process serves the seat's verbs on the bus to the
|
|
console, to tools and to the mesh's interface. The same verbs are served on a local socket on the
|
|
machine, which only the host may use. **The host creates, inspects and removes its containers
|
|
through that socket and nothing else.** If the holder does not answer, the host creates nothing. It
|
|
says so in its report, naming the seat. It never falls back to the command line.
|
|
|
|
**A container needs the seat held on its machine.** An assignment that delivers a container on a
|
|
machine whose runtime seat is unheld is refused, naming the seat and its candidates
|
|
([ADR 0165](0165-container-runtime-is-what-a-machine-can-run-and-a-running-runtime-is-its-holders-health.md)).
|
|
Mounting the runtime's socket into a container is granted by the seat, not by the capability. The
|
|
socket's path is the holder's to state, because podman's is not docker's.
|
|
|
|
**The runtime module owns the runtime's configuration.** Its settings are declared with defaults
|
|
([ADR 0164](0164-a-setting-is-declared-with-its-default-its-meaning-and-what-changing-it-costs.md)):
|
|
the resolver containers use, the registries it trusts, log rotation, and keeping containers through a
|
|
daemon restart. The module is given the resolver's address and the mesh's registry as values; no other
|
|
module writes the runtime's file or declares its service.
|
|
|
|
**The first machine is bootstrapped with the holder, and adopted afterwards.** The foundation bundle
|
|
already installs the runtime's package and service. It also carries the holder's process, delivered as
|
|
a binary the way the host is ([ADR 0142](0142-the-mesh-delivers-its-own-components-as-binaries.md)).
|
|
When the runtime module is assigned, it adopts what the bundle made, as the store and broker modules
|
|
adopt theirs ([ADR 0078](0078-the-store-and-broker-are-modules.md)).
|
|
|
|
## Consequences
|
|
|
|
- **The migration on the running mesh has a fixed order:**
|
|
1. The resolver module and the private network stop writing the runtime's file
|
|
([issue 190](../04-ISSUES/190-the-runtimes-configuration-is-written-by-modules-that-are-not-the-runtime/00-report.md)).
|
|
The runtime module takes the same file in the same push. Otherwise the controller refuses two
|
|
modules declaring one path.
|
|
2. The runtime module is assigned to every machine and adopts the runtime there. Each machine's
|
|
hand-written configuration is read before the first push, because the module's defaults
|
|
replace what differs.
|
|
3. The controller seeds the seat and enforces the container requirement.
|
|
4. The host releases the version that uses the holder.
|
|
5. The host's command-line path is removed in the release after every machine's holder answers.
|
|
Until then, the host reports per machine which path it used.
|
|
- **Every container the host makes depends on the holder's process.** A crash-looping holder stops
|
|
new containers on its machine. Running containers are unaffected. The host's report names the cause.
|
|
- The process form of a module's own code must serve tools on the live mesh before this ships. Only the
|
|
showcase declares it, and [issue 117](../04-ISSUES/117-a-modules-own-code-is-a-container-and-a-process/01-diagnosis.md)
|
|
found the showcase's tools declared in a form nothing runs. The runtime module is the first whose
|
|
tools cannot fall back to a container.
|
|
- A user interface subscribing to events directly does not exist. Today a reader of events is a module
|
|
that consumes them. The mesh's container view is a module, or waits for that path.
|
|
- The operator's decision to remove the third-party interface by hand needs no mechanism. No
|
|
module-retires-module rule is introduced.
|
|
- **What got harder:** the host gains a dependency it did not have, and a first machine's bundle gains
|
|
a component. The direct path was simpler and is what makes a runtime a black box to the rest of the
|
|
mesh.
|
|
|
|
## How this is checked
|
|
|
|
| Rule | Checked by |
|
|
|---|---|
|
|
| The seat is the mesh's own, node-scoped, with its verbs and events | A catalogue test on the default seats; registration refuses a claimant that does not serve every verb (design 33's existing check) |
|
|
| Creating or removing a mesh-held container is the host's alone | A test of the runtime module's verbs: create or remove of a container carrying the host's label, from any caller but the host's socket, is refused naming the assignment; the same verbs on an unlabelled container succeed |
|
|
| The host uses the holder and never the command line | A host test with a fake holder on the local socket: every container operation goes to it, and with the holder absent the apply creates nothing and reports the seat; after step 5, the host carries no command-line runtime code (checked by build: the package is gone) |
|
|
| A container needs the seat held | A resolution test refusing a containerised assignment on a machine with the seat unheld, naming the seat |
|
|
| Socket mounts are granted by the seat | A catalogue test: a module mounting the runtime's socket on a machine whose holder states a different path is refused |
|
|
| No other module writes the runtime's file | The existing collision check, once the private network's computed resources are inside it ([issue 190](../04-ISSUES/190-the-runtimes-configuration-is-written-by-modules-that-are-not-the-runtime/00-report.md)) |
|
|
| Live | `seats` lists `node-container-runtime` held on every machine; the node listing shows each machine's containers, strays included, from the seat's `list` verb; a container started by hand appears as an event on the bus |
|
|
|
|
## References
|
|
|
|
- [ADR 0121](0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md), [ADR 0129](0129-a-seat-carries-the-protocol-of-its-role.md), [ADR 0132](0132-a-seat-carries-the-tools-its-holder-must-serve.md), [ADR 0159](0159-a-tool-call-names-the-machine-and-a-holder-serves-its-seats-verbs.md), [ADR 0160](0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md), [ADR 0161](0161-what-deserves-a-seat.md)
|
|
- [ADR 0150](0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md), [ADR 0142](0142-the-mesh-delivers-its-own-components-as-binaries.md), [ADR 0078](0078-the-store-and-broker-are-modules.md), [ADR 0005](0005-the-node-host.md)
|
|
- [ADR 0164](0164-a-setting-is-declared-with-its-default-its-meaning-and-what-changing-it-costs.md), [ADR 0165](0165-container-runtime-is-what-a-machine-can-run-and-a-running-runtime-is-its-holders-health.md), [issue 190](../04-ISSUES/190-the-runtimes-configuration-is-written-by-modules-that-are-not-the-runtime/00-report.md)
|
|
- [Design 26 — the seats](../03-DESIGN/01-to-be/26-the-seats.md), [design 33 — the tools the mesh answers](../03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md)
|
|
- mesh-host `internal/apply/apply.go` (the runtime lookup and the command line it drives)
|