The installer carries a builder and builds the control plane it raises

It carried the thing it was going to run; it now carries the thing that makes
it. One artifact either way — but a mesh raised this way holds a control plane
it built from a repository and a commit it can name, and can therefore build
again. A mesh handed a finished image could not, and had no way to find that
out until somebody needed it to.

A build step sits between load and bundle, because the bundle must name an
image and that image no longer arrives finished. Everything after it is
unchanged: a locally built image is named by the digest of its own
configuration, which is exactly what the carried one was named by.

Refused in preflight when nothing says what to build, so a run that cannot
finish says so before it has changed anything.
This commit is contained in:
2026-09-13 04:08:58 +02:00
parent cab83b61c8
commit e1a2fe7323
10 changed files with 312 additions and 37 deletions
+27 -10
View File
@@ -51,15 +51,16 @@ const usage = `mesh-bootstrap — make a bare machine into a mesh
version
1 preflight what has to be true before anything is changed
2 load the control plane's image, carried in this installer
3 bundle the substrate, named for this machine
4 apply raise it
5 verify it is up, and the control plane replies
6 enrol this machine becomes the mesh's first node
7 registry install the module that gives this mesh an image store
8 publish push the control plane's image into it, for its first digest
9 control reinstall the control plane as an ordinary module, pinned to that digest
10 retire drop the temporary control plane; the host removes it
2 load the builder's image, carried in this installer
3 build the control plane, from its own repository and a commit
4 bundle the substrate, named for this machine
5 apply raise it
6 verify it is up, and the control plane replies
7 enrol this machine becomes the mesh's first node
8 registry install the module that gives this mesh an image store
9 publish push the control plane's image into it, for its first digest
10 control reinstall the control plane as an ordinary module, pinned to that digest
11 retire drop the temporary control plane; the host removes it
--bundle the substrate template to build this machine's bundle from
(default ` + defaultTemplate + `)
@@ -67,8 +68,14 @@ const usage = `mesh-bootstrap — make a bare machine into a mesh
(default ` + defaultOut + `)
--state where this node records what it has applied
(default ` + store.DefaultPath + `)
--source the repository the control plane is built from, on a mesh that
already exists — not the one being raised
--source-ref the commit to build. A branch is a moving target somebody else
controls, and what is cloned here is the trust anchor for
everything this mesh will ever run
--source-path the module's directory inside that repository, if not its root
--catalog a checkout of the mesh's catalogue, holding the registry's and the
control plane's manifests. Without it this stops after step 5
control plane's manifests. Without it this stops after step 6
--node the name this machine is known by (default: its hostname)
--registry where this mesh keeps its own images (default ` + defaultRegistry + `)
every node pulls the control plane from this, so on a mesh of more
@@ -83,6 +90,10 @@ const usage = `mesh-bootstrap — make a bare machine into a mesh
--dry-run everything that does not change the machine
--json machine-readable output
The installer carries a builder, not a control plane. What raises a mesh is therefore
the same thing that will maintain it, and the control plane a mesh ends up running is
one it built itself, from a repository and a commit it can name and build again.
Genesis is a pivot: a temporary control plane installs the registry that makes it
permanent. The temporary one is called temp-mesh-control and the permanent one is
called mesh-control, so they are two containers with two owners and there is nothing
@@ -175,6 +186,12 @@ func newFlagSet(opts *bootstrap.Options, jsonOut *bool) *flag.FlagSet {
set.StringVar(&opts.State, "state", opts.State, "where this node records what it has applied")
set.StringVar(&opts.Catalogue, "catalog", opts.Catalogue,
"a checkout of the mesh's catalogue; without it this stops after the substrate")
set.StringVar(&opts.Source.Repository, "source", opts.Source.Repository,
"the repository the control plane is built from, on a mesh that already exists")
set.StringVar(&opts.Source.Ref, "source-ref", opts.Source.Ref,
"the commit to build; a branch is a moving target somebody else controls")
set.StringVar(&opts.Source.Path, "source-path", opts.Source.Path,
"the module's directory inside that repository, if not its root")
set.StringVar(&opts.Node, "node", opts.Node, "the name this machine is known by")
set.StringVar(&opts.Registry, "registry", opts.Registry, "where this mesh keeps its own images")
set.StringVar(&opts.Host, "host", opts.Host, "the mesh-host binary on this machine")