81 lines
4.0 KiB
Markdown
81 lines
4.0 KiB
Markdown
---
|
|
status: resolved
|
|
opened: 2026-10-03
|
|
located-in:
|
|
- mesh-controller
|
|
- mesh-host
|
|
fixed-by:
|
|
- mesh-host#86
|
|
- mesh-controller#252
|
|
- mesh-controller#253
|
|
- mesh-host#88
|
|
amended-design:
|
|
---
|
|
|
|
# 213 — The controller is a Go program, and it still runs in a container
|
|
|
|
## What was observed
|
|
|
|
2026-10-03. The controller — the program that holds the `mesh-controller` seat and answers its
|
|
verbs (`status`, `nodes`, `push`, `assign` …), composes every machine's declaration and plans the
|
|
builds — runs on its machine as a container built from an image:
|
|
|
|
```
|
|
mesh-controller Up … (docker ps on the machine that runs it)
|
|
```
|
|
|
|
It is written in Go and compiles to one static binary, as the node host does. The host is delivered
|
|
as a bundle and run as a process; the node's tool runtime now is too
|
|
([ADR 0193](../../02-DECISIONS/0193-every-bundle-the-runtime-serves-is-launched-and-the-runtime-knows-no-language.md)).
|
|
The controller is the one piece of the mesh's own Go code still shipped as an image.
|
|
|
|
## Why it matters beyond this instance
|
|
|
|
[ADR 0188](../../02-DECISIONS/0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md)
|
|
§1 says a module's own code is bundles, never an image, and §3 that a bundle that is a service is a
|
|
`process` the host runs. The controller breaks the rule it is the mechanism of: the registration
|
|
gate that will refuse an image of a module's own code has to exempt the controller, or refuse it.
|
|
It also costs what an image costs — a container runtime on its machine as a hard requirement,
|
|
eight mounts standing in for files a process would simply read, an image rebuild for a binary
|
|
change — and
|
|
every restart of it is a container recreation, which is how the controller restarts in the middle
|
|
of a plan today.
|
|
|
|
## What a fix has to settle
|
|
|
|
- The controller's module declares a Go bundle (`system`, `binary`) and a `process` running it
|
|
(`./<binary>`, mesh-host #81), with its credential and store connection as files and words, not
|
|
container mounts and a container network name.
|
|
- What the container gives it now that a process would not: it runs on the host's network already,
|
|
as an unprivileged user (65534), with eight mounts. Each mount named and replaced by a path, and
|
|
the user by an account the host declares.
|
|
- The handover: the controller restarting itself as a process, on the one machine that runs it,
|
|
without a window where nothing answers the mesh's verbs.
|
|
|
|
Located only by owner; the move is a change of the controller's module and its deployment, not of
|
|
its code.
|
|
|
|
## Fix prepared (2026-10-04)
|
|
|
|
Three changes. mesh-host#86, merged: a process may name the container it `replaces`, and the host
|
|
removes that container only once the process has stayed up across two checks. mesh-controller#252,
|
|
awaiting the operator's merge: the controller's composition for a service process, and two
|
|
controllers safe together for the handover — the second stands by on the controller's consumers
|
|
until the first lets go, and all plan work holds one advisory lock. mesh-controller#253, held: the
|
|
controller's manifest as a Go bundle and a process. It waits on
|
|
[issue 223](../223-a-new-mesh-installs-its-controller-as-a-container/00-report.md), because with it a
|
|
new mesh cannot be installed.
|
|
|
|
## Resolved
|
|
|
|
Proven 2026-10-04 on the control machine: after the manifest change was merged and pushed, the host
|
|
created the controller's account, ran its preparation step, started the controller as a process,
|
|
found it up across both checks and removed the container. The controller now runs as its own account
|
|
from its bundle, no controller container remains, its seat answered throughout, and the merge's own
|
|
plan finished all three tiers under the new process.
|
|
|
|
One fault on the way, fixed before it could leave two controllers or none: the host read the account
|
|
not existing yet as a user database that did not answer — it matched the exit as text in a wording
|
|
its own runner did not use — so the first apply stopped at the account and the container kept serving,
|
|
which is the handover's safe failure (mesh-host#88).
|