[feat] push in waves for cross-repository layer dedup#521
Open
peakschris wants to merge 2 commits into
Open
Conversation
Collaborator
|
Thanks for this optimization! I feel like it would be even better if we could improve the upstream go-containerregistry instead, but if this meaningfully improves performance then let's do it. |
malt3
approved these changes
May 16, 2026
malt3
requested changes
May 16, 2026
Collaborator
malt3
left a comment
There was a problem hiding this comment.
There's an issue here:
nogo: nogo: error running analyzers: 32 analyzers skipped due to type-checking error: external/rules_img_tool+/cmd/deploy/deploy.go:165:9: undefined: waveGroup
Author
Thanks!
Fixed |
malt3
approved these changes
May 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
multi_deploy: deduplicate shared layers via wave-based push scheduling
When multiple push targets in a
multi_deployshare layers — for example, when several service images are built from the same intermediate layer — the deploy tool currently re-uploads those layers to every target repository independently.Problem
The OCI cross-mount mechanism (
POST /v2/{repo}/blobs/uploads/?mount={digest}&from={source}) lets a registry copy a blob server-side from another repository on the same registry, transferring zero bytes from the client. go-containerregistry supports this viaremote.MountableLayer, and the VFS already wraps base-image layers with mount hints derived from the pull source.However, cross-mounting only works once the source blob is fully present in the registry.
remote.MultiWriteprocesses push targets concurrently: when pushing toreg/svc-aandreg/svc-bat the same time, both issueHEAD /v2/{repo}/blobs/{digest}for the shared layer, both receive 404, and both fall back to a full upload before either has finished. The API has no way to express "upload this layer once and cross-mount it everywhere else" within a single call because the mount hint is advisory — if the source is not yet present the registry rejects it and the client must upload anyway.Solution
Introduce a wave-based push scheduler (
img_tool/cmd/deploy/waves.go) that enforces the required ordering outside the library:remote.MultiWritestill runs concurrently within the wave.MountableLayerhints succeed and the client transfers zero bytes.Same-registry, same-repository operations need no wave dependency (the registry deduplicates within a repository via HEAD checks). Operations on different registries form no dependency either, since cross-registry mounting is not required by the OCI Distribution Specification.
Changes
img_tool/cmd/deploy/waves.go—waveGrouptype andplanPushWavesfunctionimg_tool/cmd/deploy/deploy.go— wave-based push loop; planning runs beforevfsBuilder.Build()so hints are passed in via the builder rather than as a post-build mutationimg_tool/pkg/deployvfs/deployvfs.go—vfsBuilder.WithCrossMountHints()method; hints are merged inBuild()with base-image hints retaining priorityimg_tool/cmd/deploy/waves_test.go— 13 cases covering the wave assignment algorithmimg_tool/pkg/deployvfs/deployvfs_test.go— 3 cases forWithCrossMountHintsexercised through a realBuild()callNo Bazel rule changes required.