feat(template): isolate template-build compression with [template_build] switch - #236
Conversation
…ld] switch Add a dedicated [template_build] compression section (enabled/algorithm/ workers, all defaulting off) that governs snapshot capture during template builds, fully isolated from [memory_snapshot]. When enabled, both memory layers and the sealed rootfs read-write layer are written ZFile-compressed: the daemon still seals the upper raw, and the main process recontainerizes only the staged snapshot artifact via compact_layers while the live runtime keeps referencing the raw sealed layer. Ordinary pause/capture is unchanged: memory layers keep consulting only [memory_snapshot] and rootfs seals stay raw. Extra drives stay raw. The descriptorless-delta filename allowlist learns snapshot.zfile.commit so posixfs/OSS/ACR publish paths accept the compressed seal. The compression algorithm enum is renamed to OverlaybdCompressionAlgorithm (serde wire values unchanged) now that it backs more than memory snapshots.
|
🔍 OpenCodeReview found 4 issue(s) in this PR.
📄
|
| pub struct TemplateBuildConfig { | ||
| #[config(default = false)] | ||
| pub compression_enabled: bool, | ||
| #[config(default = "lz4")] | ||
| pub compression_algorithm: OverlaybdCompressionAlgorithm, | ||
| /// Number of blocking threads used to compress 4KiB blocks within a | ||
| /// layer. 1 = sequential (identical output layout at any value). | ||
| #[config(default = 1)] | ||
| pub compression_workers: usize, | ||
| } |
There was a problem hiding this comment.
TemplateBuildConfig is the only newly added nested config type not included in impl_config_default!. As a result, callers cannot construct it with TemplateBuildConfig::default() or use struct-update syntax, unlike MemorySnapshotConfig and the other nested configuration types. Add it to the default-implementation list to keep the public configuration API consistent and make future field additions less disruptive to callers.
Suggestion:
| pub struct TemplateBuildConfig { | |
| #[config(default = false)] | |
| pub compression_enabled: bool, | |
| #[config(default = "lz4")] | |
| pub compression_algorithm: OverlaybdCompressionAlgorithm, | |
| /// Number of blocking threads used to compress 4KiB blocks within a | |
| /// layer. 1 = sequential (identical output layout at any value). | |
| #[config(default = 1)] | |
| pub compression_workers: usize, | |
| } | |
| pub struct TemplateBuildConfig { | |
| #[config(default = false)] | |
| pub compression_enabled: bool, | |
| #[config(default = "lz4")] | |
| pub compression_algorithm: OverlaybdCompressionAlgorithm, | |
| /// Number of blocking threads used to compress 4KiB blocks within a | |
| /// layer. 1 = sequential (identical output layout at any value). | |
| #[config(default = 1)] | |
| pub compression_workers: usize, | |
| } | |
| // Also add `TemplateBuildConfig` to `impl_config_default!(...)` below. |
| let rewritten_lowers = rewrite_lowers_with_owned_runtime_suffix( | ||
| image_config.lowers, | ||
| output_dir, | ||
| appended_layer, | ||
| MANAGED_BASE_LAYER_FILE, | ||
| // Rootfs layers must stay raw: only memory snapshots may be compressed. | ||
| OverlaybdCompactOutput::Raw, | ||
| // Rootfs seals stay raw unless the caller (template builds) requested | ||
| // compressed seal output; memory snapshots have their own switch. | ||
| seal_output, | ||
| ) |
There was a problem hiding this comment.
When the runtime-owned suffix exceeds the compaction budget, appended_layer has already been compressed to ZFile above and is then fed into compact_layers(..., seal_output) with the rest of the suffix. Although mixed ZFile input is supported, this decompresses and recompresses the freshly sealed layer, doubling expensive compression I/O for long-lived/derived template chains. Decide whether suffix compaction is needed before recontainerizing: compact the raw appended layer directly when over budget, and create snapshot.zfile.commit only for the non-compaction path. Add a test covering the over-budget branch.
| if !ConfigManager::global_config() | ||
| .template_build | ||
| .compression_enabled | ||
| { | ||
| return Ok(()); | ||
| } |
There was a problem hiding this comment.
This check does not exercise the new compression path under the repository's default configuration (template_build.compression_enabled defaults to false), so a normal integration-test run can pass even if the builder never propagates compression. Add a dedicated test setup/configuration that enables template-build compression rather than making the only end-to-end assertion a no-op. That test should also open the ZFile and compare options().algo with template_build.compression_algorithm; is_zfile alone would not catch an implementation that ignores the configured LZ4/Zstd choice.
What
Adds a dedicated
[template_build]compression section (compression_enabled/compression_algorithm/compression_workers, all off by default). When enabled, template builds capture snapshots with both memory layers and the sealed rootfs read-write layer written as ZFile-compressed overlaybd layers. Pause/capture of ordinary running sandboxes is unchanged.Why
The only pre-existing compression switch,
[memory_snapshot].compression_enabled, covers memory layers only (rootfs seals always stay raw) and is shared by every capture path — so compressing template-built artifacts forced operators to also pay compression CPU on every production pause. Template-built snapshots are the distribution vehicle for sandbox images; compressing their memory and rootfs delta layers shrinks repository storage and cross-node transfer, and that choice should be decoupled from the runtime pause policy.Related issue
N/A — no tracking issue.
Scope and non-goals
Included: the
[template_build]config section; compression-override plumbing in the template-build capture path; ZFile recontainerization of the sealed rootfs layer; the delta-filename convention extension; unit and integration tests; documentation.Intentionally excluded: the orchestrator pause/capture path (memory layers still consult only
[memory_snapshot], rootfs seals stay raw); extra drives (stay raw); ublk-daemon and theRestackSnapshotRPC (the daemon still seals raw); publish/resume/P2P code (existing zfile compatibility is reused); no per-API compression knob.Design and behavior changes
TemplateBuildConfigregistered as the[template_build]section. The shared algorithm enum is renamed toOverlaybdCompressionAlgorithm(serde wire valueslz4/zstdunchanged).FirecrackerSandboxgainssnapshot_compression_override, set only by the template runner;snapshot_to_dirprefers the override for both the memory output and the rootfs seal output.snapshot.commitas before (the live runtime keeps referencing it); the main process then recontainerizes only the staged artifact intosnapshot.zfile.commitvia the existingcompact_layersmachinery. The over-budget compaction path also honors the requested seal output.local_layer.rslearns thesnapshot.zfile.commitdelta filename (shared by the posixfs/OSS/ACR publish paths).[memory_snapshot].compression_enabled. If that switch is on but[template_build]is off, template artifacts stay raw.Compatibility and operations
[template_build]section; every key has a default (off /lz4/ 1), existing configs load unchanged.snapshot.zfile.commitname; ZFile is the standard overlaybd layer format that resume paths already read natively. Managed-layer bytes of template-built snapshots may now be ZFile (already true for memory layers).Validation
make fmtmake clippymake test-unitmake -C services test(required whenservices/changes)maketargetCommands and results:
Skipped checks and reasons: no benchmark — the non-template hot path is untouched (one extra
Optioncheck per capture); the compression cost (one extra read+write pass of the sealed layer) only applies to template-build captures with the switch on, by design.services/and generated code untouched, so those checks are N/A.Risks and reviewer notes
[memory_snapshot].compression_enabled; deployments relying on the old coupling must set[template_build]explicitly.src/sandbox/firecracker/overlaybd_snapshot.rs(staging recontainerization),src/sandbox/firecracker/sandbox.rs(override precedence),src/image/local_layer.rs(filename convention).Checklist