microvm: write container rootfs to host disk instead of guest memory - #846
microvm: write container rootfs to host disk instead of guest memory#846Lucky Abolorunke (Oneimu) wants to merge 1 commit into
Conversation
|
/assign Benjamin Elder (@BenTheElder) |
Benjamin Elder (BenTheElder)
left a comment
There was a problem hiding this comment.
Is it possible to do the read-only image rootfs + overlay upper on the host side behind the virtiofsd mount, and then tar up the upper if a snapshot is requested (and move the virtiofs to auto instead of always), or does that not work? That might be somewhat less complex and less expensive than the additional virtiofsd if it works.
| // An error return between here and the join MUST drain the goroutine (the | ||
| // deferred receive below): returning with the untar still writing would let | ||
| // a retried restore's own untar race it inside the same directory. | ||
| hasUpper := snapshotHasRootfsUpper(restoreDir) |
There was a problem hiding this comment.
🤖 nit 🟢 – The legacy branch is the one entry path that leaves the upper directory as it found it. Cold boot calls resetRootfsUpperDir and a disk-upper restore's untarRootfsUpper starts with RemoveAll, but a no-tar restore touches nothing. Teardown's removal is warn-and-continue, and the directory sits on the BasePath hostPath, so it also survives an ateom kill before teardown runs.
When a stale directory does survive into a legacy restore, actorHasDiskUpper reports true for an actor whose upper is really in guest memory. The next FULL checkpoint then tars that directory and emits a rootfs-upper.tar the guest never used, and the restore after it stages a third virtiofsd for a share the snapshot's config.json does not reference. The real upper still comes back from memory, so this is a mislabelled snapshot rather than a broken one — but the mislabel is sticky.
Calling resetRootfsUpperDir on this branch too would make "directory absent" mean the same thing on all three entry paths.
| // guest over virtio-fs so rootfs writes land on host disk instead of guest | ||
| // RAM. Unlike the durable-dir volumes it is owned entirely by ateom (created | ||
| // at cold boot, archived at checkpoint, removed at teardown); atelet never | ||
| // touches it. |
There was a problem hiding this comment.
This package is used for paths that need to be shared between ateom and atelet, or at least multiple ateom implementations, is there a reason to expose this?
Problem
Each container's rootfs in
ateom-microvmis an overlay whose writable upper lived on a tmpfs inside the guest: every byte an actor wrote consumed guest RAM 1:1, and writes failed withENOSPCat the tmpfs cap — 20% of guest RAM, ~392 MiB on the standard 2 GiB guest (measured). Any actor unpacking a checkout, pip-installing, or logging heavily hits a hard, workload-dependent crash, and write-heavy actors degrade worker density for their whole lifetime.Changes
The overlay upper moves to host disk: a third virtio-fs share (
ateUpper— ownvirtiofsd, write-through,cache=auto,--xattr), serving a per-actor host directory (<actor>/rootfs-upper/), with each container's upper/work as sibling directories under it. Rootfs writes now cost host disk, not guest RAM, and are no longer capacity-capped. There is no configuration surface — this is the only mode, matching the gVisor runtime's no-knob stance.Snapshot/restore integration:
rootfs-upper.tar, taken while the guest is paused (write-through ⇒ coherent) and concurrently with the CH memory snapshot and durable-dir tar — the paused window costs the slowest artifact, not their sum.virtiofsdstarts.rootfs_upper=0, no tar emitted).Enabling fixes (required for any overlay upper on virtio-fs):
index=off,metacopy=off,userxattr(guest kernel returnsEINVALotherwise).tarutilnow round-trips overlay deletion metadata: whiteout device nodes (mknodat, parent-fd contained) anduser.overlay.*opaque-directory xattrs (PAXSCHILY.xattrrecords, restored through the extraction root so a crafted archive cannot write outside it). Without these, deleted files/directories silently reappeared after resume.How it was tested
Unit tests (all pass; privileged tests executed as root inside a kind node, no skips):
tarutilround-trips: contents/modes/mtime/symlinks/hardlinks, device nodes (incl. a literal 0:0 whiteout),user.*xattr PAX round-trip (incl.user.overlay.opaque), extraction-escape rejections.virtiofsdargs (--xattronly on the upper share), snapshot config rewriting for all three fs tags.End-to-end (kind cluster, counter demo actor with a durable-dir volume — so every run also covers durable-dir coexistence):
virtiofsds (RO lower / durable / upper,--xattron the upper); a file written inside the guest appears in the hostrootfs-upper/directory.rmof an image file produced a genuine overlayfs whiteout on the host (char 0:0,nlink 2— kernel-created, viamknodthroughvirtiofsd); in-guestrm -rf && mkdirof an image directory produceduser.overlay.opaque="y"on the host upper (xattr passthrough).snapshot∥durable_dir∥rootfs_upper); after restore, verified inside the guest: written marker present, deleted file still absent, replaced directory still empty; durable counter state intact.rootfs-upper.tar(rootfs_upper=0);DATA_ON_GOLDENresume stitches the golden'srootfs-upper.tar+ memory with the actor's own durable tar (verified in atelet download logs), preserving actor data isolation.virtiofsds), and its re-checkpoint correctly emits no upper tar.Performance
in progress.