Repository navigation
Feat/images max size - #176
Merged
Merged
Conversation
Adds images --max-size <size>, the mirror of --min-size: images that would free more are evicted only once nothing else is left. Size is what removal frees, the bytes in layers no other image shares, which is also what a re-pull fetches and unpacks. With --lru, --stale-after <duration> exempts images unused for longer from both size rules, so a replaced build or retired challenge still goes by age rather than being held until nothing smaller is left. Off by default, so --min-size behaves as before unless it is set. --max-size below --min-size is refused. With --lru, the order is: stale images, then the rest, then images under --min-size, then images over --max-size, oldest first within each. Why: on the cork workers (75 GB, --threshold 89 --target 84 --min-size 100MiB --lru) eviction goes oldest first among images of 100 MiB or more, with no regard to size within that group, so a multi-GB image is as likely to go as a 100 MiB one of the same age. From cork's launch records, 2026-09-27..10-07: 684 of 90,688 launches pulled; 68 of those re-pulled the same build on the same worker after eviction and account for 67% of all pull wait. The worst are 2-3.5 GB images at 20-46 s each, while non-pulled launches are p99 279 ms and small re-pulls take ~0.5 s. Deletion cost was measured too (Docker 29.8, cold caches): 800 MB in 100 files deletes in 0.02 s, 800 MB in 100k files in 0.8-1.1 s whether as one image or ten, and a create loop got 1 iteration through the single large delete against 9-10 through the ten small ones, since the layer store lock is released between images. So --min-size's premise (fewer, larger removals are cheaper) does not hold, and small removals stall launches less. --stale-after requires --lru, whose record is the only source of when an image was last used; --max-size works on size alone without it. Like --lru, --stale-after keeps its last value when repeated, so a deployment can append it to a command that may already carry it. An image stamped 0, seeded when the record began, ages from when the record began, which the record now keeps as a first line `# began <secs>` (1.4.0 skips it as malformed; a 1.4.0 record is taken to begin when this release first saves it). Counting a seeded image as unused forever made every image stale on the first pass after a record was created or deleted, and they tied at 0, so the largest went first. A record that would make something stale yet shows no use within --stale-after is taken to be no longer kept: that pass treats nothing as stale and warns. Bounds no pass can use (--target at or above --threshold, --max-size below --min-size) are refused at startup. A pass only logs its errors, so a bad bound used to leave the process exiting 0 while evicting nothing. Sizes are those at the start of a pass, and the README says so: an image left as the only owner of shared layers mid-pass keeps its place until the next pass. Listing images after every removal would catch it (~12 ms per list at ~300 images, measured), but on the cork workers every large shared base belongs to images already over 512 MiB, so it was left out.
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.
Adds images --max-size , the mirror of --min-size: images that would free more are evicted only once nothing else is left. With --lru, --stale-after (no default) lets images unused for longer go by age alone, so replaced builds don't hold disk. Order with --lru: stale, the rest, under --min-size, over --max-size, oldest first within each group.
On cork's workers, re-pulling evicted builds accounts for 67% of pull wait. The worst re-pulls are 2–3.5 GB images at 20–46 s each, against about 0.5 s for a small one. Measured deletes cost per file rather than per byte, and several small deletes stall container creates less than one large one.
The use record gains a # began first line, which 1.4.0 skips. Images seeded when the record started age from that time, so a new or deleted record doesn't make every image stale at once. A record showing no use within --stale-after triggers a warning instead of making everything stale. Bad --target/--threshold or size bounds are now refused at startup; before, a pass logged the error and exited 0 without evicting anything.
Verified: 72/72 tests against a live Docker 29.8 daemon, plus live eviction-order and record scenarios. README and CHANGELOG updated.