Files
hq/04-ISSUES/026-the-data-directories-are-not-declared/00-report.md
T
jschoubben 3f00d3b413 026 filed; 025 corrected; the image store is a module
Three corrections, two of them to things I wrote today.

026 is the serious one. Four modules mounted fourteen host paths nothing
declared — the mail spool, the databases, the object store's data. The
runtime creates those as root, so owner and mode go unapplied, and the
rule that keeps a directory holding data the mesh did not put there is
written in terms of declared directories. It reached the configuration
and missed the data. The cause was carrying compose files across: a
container shape that can express one gets filled in like one.

025 claimed nothing turns a tag into a digest. That is false, and the
answer was designed and built before I wrote it. A module names an
artifact, not an image, and `kind: upstream` mirrors somebody else's
image into the mesh's own registry, pinned by the digest it lands with.
The two-document split the issue described as the shape of a fix is the
design. Pinning twelve images by hand was treating the symptom, and left
them pointing at a public registry rather than the mesh's.

And the image store was written up as something the mesh does. It is an
ordinary module — considered for the substrate and removed, because the
test is whether the control plane needs it before its first instruction,
not whether it can grant itself one. So somebody's own registry is the
same module as the mesh's.
2026-09-01 16:10:13 +02:00

3.2 KiB

status, opened, located-in, fixed-by, amended-design
status opened located-in fixed-by amended-design
located 2026-09-01
mesh-control

026 — The data directories are mounted and never declared

Symptom

Four modules mount fourteen host paths that no resource in those modules declares:

gitea      /services/gitea/gitea
postgres   /services/postgres/db-data
minio      /services/minio/data/data1-1
mailu      eleven more, including the mail spool and the admin database

Each is a bind mount on a container. None is a directory resource. The mesh has never heard of any of them.

What that costs

They are created by the container runtime, as root. A bind mount whose source does not exist is created for you, owned by root, with whatever mode the runtime picks. So owner and mode — which exist precisely so a module can say who its data belongs to — are silently not applied to the only directories that hold data.

The protection that exists for exactly this does not reach them. A directory the mesh declared and no longer wants is kept, not removed, when it holds anything the mesh did not put there (ADR 0030). That rule is the answer to what happens to my data when a module goes away, and it is written in terms of declared directories. An undeclared one is not protected by it, because the mesh does not know it is there.

So the single rule guarding against data loss covers the configuration directories, which are cheap to lose, and not the data directories, which are the reason the rule exists.

Where it came from

These manifests were written by reading the arrangement being replaced and carrying its docker-compose files across — service, image, ports, volumes, environment — into the new manifest's container shape. That shape can express all of it, which is what made the transliteration feel like progress.

A container shape that can express a compose file will be filled in like a compose file. The mesh's model is larger than that: a directory is a thing the mesh owns, with an owner and a mode and a rule about what happens when it is no longer wanted. A volume line borrowed from compose declares none of it, and nothing complains, because a bind mount source is a string.

What a fix has to keep

  • Every host path a container mounts is declared. If a module wants a directory on the machine, it says so, with who owns it and what mode — and gets the removal rule with it.
  • The check is mechanical. A person comparing volumes against declared directories by hand is the process that produced this. It is a few lines against the manifest and belongs beside the other manifest checks.
  • Not by inventing directories at apply time. The host creating what a mount needs would make the mesh's ownership of a directory depend on which resource mentioned it first, and would put the same undeclared path back a layer down.

Not yet answered

Where a module's data should live at all. These paths were inherited whole from the arrangement being replaced, which put everything under one directory per service. Whether that is right here is a separate question, and a bigger one — it decides what a person backs up, and what survives a module being removed.