An image built unnumbered is published by its digest; the builder's version.numbered now publishes it under its version, sending nothing. The late publish moved into buildstep, so mesh-build-go and mesh-build-image share one. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
67 lines
5.8 KiB
Markdown
67 lines
5.8 KiB
Markdown
# mesh-build-image — the image build module
|
|
|
|
Design 47, release R4c-9 (novox/hq ADR 0487, ADR 0466 §1, ADR 0469; issue 1703). The module that builds a module's
|
|
`image` artifact from the Dockerfile in the module's own directory, on a build machine, as an account of its own
|
|
(`runs-as`, no login shell, home at mode 0700). It serves every module's image, whatever the base, so it is not a
|
|
build module for one module. It claims no seat: it is assigned to the build machines and runs dark until the builder
|
|
uses it.
|
|
|
|
## Rootless
|
|
|
|
The tool is `buildah`, which the `buildah` module installs and provides as `rootless-image-build` with the machine's
|
|
reach: a machine without it refuses this module at assignment, naming `buildah`. The build runs as the module's own
|
|
account in a user namespace (`--isolation oci`), with buildah's image store and runtime state in
|
|
`/var/lib/mesh-build-image-store` (outside the home), no mount of the host, no container runtime socket, no registry
|
|
credential and an environment built from scratch.
|
|
|
|
The account's subordinate user and group ranges are not declared anywhere: the node-engine makes every `user` account
|
|
with `useradd`, which allocates them. The module's health reads `/etc/subuid` and `/etc/subgid` and is unhealthy
|
|
when the module cannot run: without a range for the account, without buildah, when a user namespace cannot be made,
|
|
or when the disk is under its floor. A node where `/dev/net/tun` cannot be opened stays **healthy** and is **not
|
|
eligible** (buildah makes a RUN line's network with pasta, which needs the tun driver; on 2026-10-28 a build node had
|
|
the device node and no driver, so every image build there failed with "Failed to open() /dev/net/tun: No such
|
|
device"): the seat's puller judges by a capacity of 0 with that reason (`capacity.<node>`, which `build_usage` shows),
|
|
so the asks go to a node that can build them, and its health says "not eligible" with the cause, so a node that
|
|
cannot build here now never holds the module's delivery for every node. The kernel module loads `tun` at boot; a look
|
|
that passes again wakes the puller.
|
|
|
|
The Dockerfile's steps may use the network (ADR 0487 §6); nothing a step can read holds a key.
|
|
|
|
## Steps
|
|
|
|
- `build_image_fetch` fetches a commit over SSH into a workspace (a base commit makes the merge preview, as the other
|
|
build modules' fetch). Long: answers a step id and ends on its key in `steps`.
|
|
- `build_image_build` builds one image artifact: `buildah bud` with the Dockerfile `from` names (in the module's
|
|
directory or a subdirectory of it) as file and the module's own directory as context, so a COPY names paths from the
|
|
module's root (issue 1703), `--target`, and the images `build.on` pins as `--build-arg`. Answers the image's digest. With
|
|
`publish: true` (a merged trunk commit only) the module's own process then writes it as an OCI layout in the
|
|
workspace and publishes it through the seat `container-image-registry` (`publish`, `publish-part`, which the manifest
|
|
`invokes`; design 51 *Publishing*) as `<module>/<artifact>` at the ask's `version` (and a `tag` only when the call gives
|
|
one): its config, layers and manifest by digest, of which only the parts the holder lacks travel. The key carries the
|
|
layout's manifest digest and the seat's reference `container-image-registry/<module>/<artifact>@sha256:<digest>`; a
|
|
publish the holder does not take fails `not stored:`. Without `publish` (a pull request) nothing is published.
|
|
An image the builder had not numbered yet is published by its digest alone; the module consumes the builder's
|
|
`version.numbered` and publishes that held digest under its version, sending nothing (`latepublish.go`, ADR 0617 §1);
|
|
a holder that no longer holds the digest fails the event, which is offered again.
|
|
- `build_image_copy` copies an upstream artifact (`module`, `artifact`, `from`) into the image seat by its `mirror`, by the
|
|
digest the manifest pins (ADR 0498 §4): the holder copies it and says `published` or `refused` on the seat's events,
|
|
which the manifest `consumes`; the step ends on that outcome (or fails `not stored:` after 30 minutes without one) and
|
|
answers the digest and the seat's reference. A `from` without a digest fails `not pinned:` before the seat is asked. It
|
|
needs no workspace, no buildah, and reads no outside registry itself. The copy's wait is kept in the state
|
|
`mirror-waits` under its digest before the seat is asked: the seat's events reach one instance of the module, which
|
|
writes the outcome into that key, and the waiting copy reads it there, woken by its watch of the state. A copy removes
|
|
its wait when it ends; one a stopped process left goes after two days. `build_image_mirror_waits` reads that state.
|
|
- It refuses, naming why, an image whose build context is a whole repository (`context`) or whose `build.on` names
|
|
another module's artifact (`unsupportedImage` in `build.go`): those forms belong to the images build-agent builds
|
|
until it is removed at R4g.
|
|
- `build_image_release {workspace}` removes a workspace at once (no guard, no floor; one already gone is no error, one a
|
|
running step holds is refused); its caller calls it once its last step answered. A failed fetch removes its own
|
|
workspace, and one no caller released is removed two hours after its last use (ADR 0509).
|
|
- A fetch and a build are refused, `refused: <node> has N GiB free under the floor of 20 GiB (on <dir>)`, and the health
|
|
is unhealthy with that text, while the work directory's or the image store's filesystem has less than 20 GiB free
|
|
(issue 1839). A copy writes nothing to the disk and is not refused.
|
|
- `build_image_step`, `build_image_steps`, `build_image_status` and `build_image_health` read.
|
|
|
|
The module holds no registry address and no registry credential: every write goes through the image seat's verbs, and
|
|
the holder checks each publish with the builder.
|