Skip to content

c8d/list: Add test and combine size#47449

Merged
vvoland merged 10 commits intomoby:masterfrom
vvoland:c8d-list-single
Mar 7, 2024
Merged

c8d/list: Add test and combine size#47449
vvoland merged 10 commits intomoby:masterfrom
vvoland:c8d-list-single

Conversation

@vvoland
Copy link
Contributor

@vvoland vvoland commented Feb 26, 2024

- What I did

  • Add unit test for Images (image list)
  • Skip images which don't match platform matcher
  • Extract and simplify some code
  • Count containers using ImageManifest

- How I did it
See commits 🙈

- How to verify it
CI

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@vvoland vvoland self-assigned this Feb 26, 2024
@vvoland vvoland added this to the 26.0.0 milestone Feb 26, 2024
@vvoland vvoland added the containerd-integration Issues and PRs related to containerd integration label Feb 26, 2024
@vvoland
Copy link
Contributor Author

vvoland commented Feb 27, 2024

$ docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
c2bf9493c1bf: Download complete 
Digest: sha256:6d9ac9237a84afe1516540f40a0fafdc86859b2141954b4d643af7066d598b74
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
busybox      latest    6d9ac9237a84   5 weeks ago   6.09MB

$ docker pull --platform linux/amd64 busybox
Using default tag: latest
latest: Pulling from library/busybox
9ad63333ebc9: Download complete 
Digest: sha256:6d9ac9237a84afe1516540f40a0fafdc86859b2141954b4d643af7066d598b74
Status: Image is up to date for busybox:latest
docker.io/library/busybox:latest

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
busybox      latest    6d9ac9237a84   5 weeks ago   12.7MB

@vvoland vvoland added area/images Image Distribution kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. kind/refactor PR's that refactor, or clean-up code labels Feb 27, 2024
@vvoland vvoland marked this pull request as ready for review February 27, 2024 11:26
Comment on lines 80 to 81
// TODO(thaJeztah): do we need to take multiple snapshotters into account? See https://github.com/moby/moby/issues/45273
snapshotter := i.client.SnapshotService(i.snapshotter)
snapshotter := i.snapshotterService
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. this means we won't be able to use multiple snapshotters (see the TODO comment above). If we do this, we should store it indexed by snapshotter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm fair enough, done.

return nil, nil, errors.Wrapf(err, "failed to get rootfs of image %s", imageManifest.Name())
}

func (i *ImageService) singlePlatformSize(ctx context.Context, imgMfst *ImageManifest) (totalSize int64, contentSize int64, _ error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is a bit confusing. I need to look into what exactly it returns; totalSize is the size for all platforms? what is contentSize in this context?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! This is for a single-arch image (so "total" for the image, in this case being the total for a single arch, correct?)

Copy link
Contributor Author

@vvoland vvoland Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, total here means both content (distributed blobs) and "unpacked" size (snaphots).

@vvoland vvoland force-pushed the c8d-list-single branch 2 times, most recently from a21249e to ffef668 Compare February 27, 2024 12:28
return s
}

return i.client.SnapshotService(snapshotter)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be stored in the map, or was it intentional to only keep a reference to the default one?


if opts.ContainerCount {
i.containers.ApplyAll(func(c *container.Container) {
if c.ImageManifest != nil && c.ImageManifest.Digest == img.Target().Digest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a follow-up; we should really document the ImageManifest field in container; I went looking to see if this was the "platform-specific" manifest, or if this was the manifest-index ("root" of the image), but the field is currently not documented.

platform = dockerImage.Platform
}

if !platformMatcher.Match(platform) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps would be worth adding your commit-message description as a comment here; this would not be obvious immediately when looking at the code.

Currently this won't have any real effect because the platform matcher matches all platform and is only used for sorting.

Curious if this would filter, wouldn't that mean that docker image ls would not include sizes for all images?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd assume it would only include the size for matching-platform images. However, I think that makes sense: if the passes in a specific platform matcher, it's because they only want to know about those particular images.

Copy link
Contributor Author

@vvoland vvoland Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what's the correct behavior here when we're reducing multiple platforms into one list item.

Hmmm good one. I feel like technically the correct behavior would be to show the total size of all images, because the single entry represents the whole multi-platform image with all platforms.

This would mean, that if we now added the --platform switch, it wouldn't really affect anything in the output.. But perhaps that's actually what we want - it should only affect the platform specific subimages.

EDIT: Actually it would also hide the multiplatform images not supporting that platform, so I think it's actually the expected behavior.

Copy link
Member

@thaJeztah thaJeztah Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah my train of thought here was that;

abcd ubuntu:latest 200MB

Is the compact view of;

abcd ubuntu:latest 200MB
 |-- ubuntu:latest X64   100MB
 |-- ubuntu:latest ARM64 100MB

So when "collapsed", it would show the summary of it all.

For sure, this is a bit of a limitation of the current means we have, and to some extent there's also something to be said for that to be showing "default" platform. But "hiding" the 100MB for the non-matching platform is also surprising (It says I have 200MB used for images, but I only see 100??)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it makes more sense to show the total size. Fixed.

Copy link
Member

@laurazard laurazard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
Just noticed a little typo/duplicated word in c8d/list: Count containers by their manifest's text:

Move containers counting out out `singlePlatformImage` and count them
based on the `ImageManifest` property.

vvoland added 5 commits March 7, 2024 16:25
Use `image.Store` and `content.Store` stored in the ImageService struct
instead of fetching it every time from containerd client.

Signed-off-by: Paweł Gronowski <[email protected]>
Avoid fetching `SnapshotService` from client every time. Fetch it once
and then store when creating the image service.

This also allows to pass custom snapshotter implementation for unit
testing.

Signed-off-by: Paweł Gronowski <[email protected]>
To ease accessing image descriptors in tests.

Signed-off-by: Paweł Gronowski <[email protected]>
Add unit test for `Images` implementation.

Signed-off-by: Paweł Gronowski <[email protected]>
Multi-platform images are coalesced into one entry now.

Signed-off-by: Paweł Gronowski <[email protected]>
vvoland added 2 commits March 7, 2024 16:26
Move containers counting out of `singlePlatformImage` and count them
based on the `ImageManifest` property.

(also remove ChainIDs calculation as they're no longer used)

Signed-off-by: Paweł Gronowski <[email protected]>
Don't save all present images,  inline the sorting into the loop
instead.

Signed-off-by: Paweł Gronowski <[email protected]>
vvoland added 3 commits March 7, 2024 16:27
Signed-off-by: Paweł Gronowski <[email protected]>
Currently this won't have any real effect because the platform matcher
matches all platform and is only used for sorting.

Signed-off-by: Paweł Gronowski <[email protected]>
@vvoland
Copy link
Contributor Author

vvoland commented Mar 7, 2024

Thanks @laurazard! This one was meant to be out of, not out out 😅

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

I wonder if (with more complexity, and more iterating needed to collect all the data) if we should benchmark some of this. Do we need to consider caching at some point? Caching is hard though (and we should not optimise if not needed); more so because the list of present images / platforms will change at any moment, so cache invalidation would now be an issue.

Comment on lines +82 to +88
s, ok := i.snapshotterServices[snapshotter]
if !ok {
s = i.client.SnapshotService(snapshotter)
i.snapshotterServices[snapshotter] = s
}

return s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For posterity / future self; I think this is fine to do, but technically this map would be "unbounded", so would allow an "unlimited" number of snapshotters to be referenced here.

I don't think there's any realistic security here (unless someone would want to DOS themselves by having a gazillion snapshotters).

@thaJeztah
Copy link
Member

Looks like this one is flaky (I think I mentioned the same one on another PR);

=== FAIL: github.com/docker/docker/integration/networking TestBridgeICCWindows/User_defined_nat_network (9.20s)
    bridge_test.go:242: assertion failed: error is not nil: Post "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.45/containers/e6bc72d3a70cd87e40bdc547f722749fb7038a26c421697cd350ebcced73db0b/start": context deadline exceeded
    panic.go:523: assertion failed: error is not nil: Error response from daemon: error while removing network: network mynat id 01daafb478bec6f00a16d87bd570a8328c8135c212575c12e29cec9a3c4a9500 has active endpoints

=== FAIL: github.com/docker/docker/integration/networking TestBridgeICCWindows (16.80s)

@vvoland
Copy link
Contributor Author

vvoland commented Mar 7, 2024

One easy thing to cache would be the readConfig calls - no need to repeatedly fetch the same blobs from the content store. Configs are small enough, and with content addressability there's no cache invalidation needed (content won't change for the same digest).

Not sure how big of an performance improvement it would bring though, it would definitely be nice to have benchmarks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/images Image Distribution containerd-integration Issues and PRs related to containerd integration kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. kind/refactor PR's that refactor, or clean-up code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants