Mount an OCI image read-only into an actor - #923
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
4e11b94 to
5cb2ccc
Compare
8eca1d8 to
416ac52
Compare
A volume can name an OCI image; the reference must be digest-pinned and mounted by at least one container. ateapi projects it into the workload spec on its own volume type.
416ac52 to
6137852
Compare
Benjamin Elder (BenTheElder)
left a comment
There was a problem hiding this comment.
huge +1 in concept, it's a fair bit of code understandably, I need to read back through it in depth. attaching one plausible looking agent finding now.
| // ImageDigest is the manifest digest the volume's ref resolved to, in the | ||
| // same form and for the same reason as OverlaySpec.ImageDigest: the GC's | ||
| // root-set scan protects an image by digest. | ||
| ImageDigest string `json:"imageDigest,omitempty"` |
There was a problem hiding this comment.
🤖 blocking 🔴 – Nothing roots these, so the GC can evict an image volume's layers while an actor is running on them. addSpecRoots in internal/imagecache/gc.go reads spec.ImageDigest and spec.Layers and never looks at spec.ImageVolumes, so a volume's digest never reaches RootSet.ImageDigests and its layer hexes never reach LayerHexes or LayerSets.
Both eviction guards then miss. The volume's image record fails the digest check and is retired, which drops its layers' refcount to zero, and the bundle-spec fallback that would otherwise save them is keyed on LayerHexes. The layers go while they are bind-mounted at <bundle>/volumes/<name>. A resume is the visible failure: setupImageVolumes calls FinalizeLayer on a directory that no longer exists.
The watermark makes it likelier rather than rarer — the GC fires under cache pressure, which is the state this feature encourages by adding images per actor.
addSpecRoots walking spec.ImageVolumes covers it. Worth giving each volume its own LayerSets signature rather than folding its layers into the rootfs one, since the signature is meant to match a record's exact layer list.
The bundle overlay spec gains ImageVolumes; ateom composes each at ateompath.ImageVolumeMountPath — a bind for one layer, an upperless overlay for several, FinalizeLayer first so whiteouts hold.
resolveImageVolumes pulls each mounted image through the layer cache and records its layers in the overlay spec; the OCI spec binds the composed volume read-only at the declared path.
The micro-VM runtime builds its own guest OCI spec, so image volumes are carried explicitly: ateompb.Container gains image_volume_mounts, staging binds each composed volume into the read-only share beside the rootfs, and the guest re-adds the binds at the declared paths.
A three-layer fixture pushed at test time: every layer visible, an upper layer shadows a lower one, a whiteout hides a file, writes are refused, and the volume survives suspend/resume.
6137852 to
33203f7
Compare
Fixes #783
Adds an
imagesource toActorTemplate'sVolumeSource: a container can mount the contents of an OCI image it does not run. This is how tooling gets into images built by third parties without rebuilding them.How it works
atelet pulls the image through the existing layer cache and records the volume's layers in the bundle's overlay spec, next to the rootfs layers. ateom composes the volume inside the bundle — the cached layers with no writable layer on top, so the mount is read-only — and the container binds it at the declared path. The volume is composed per container: containers of one actor may mount the same volume, and each gets its own mount point inside its own bundle, all backed by the same shared layers. On resume the volume is re-composed the same way.
References must be digest-pinned, the same rule as container images: a snapshot is only valid against the exact bytes it was taken with.
On micro-VMs the volume rides the same read-only virtio-fs share as the container rootfs: ateom stages each composed volume beside the rootfs on the host, and the guest binds it into the container at the declared path.