Skip to content

Conversation

@vvoland
Copy link
Collaborator

@vvoland vvoland commented Aug 24, 2022

This makes it possible to push multi-platform images if some contents are missing from the local content store, but can be fetched from a source repository.

The trick here is wrapping the ContentStore to return a fake content.Info with a containerd.io/distribution.source. label which specifies the source registry and repository for the blob. It's then used by the repository to cross-repo mount the blobs.

Caveats:

  • Doesn't work with other registries than the one which provided the missing blob.
  • Works only as long as we have a source manifest (it's deleted by buildx purge -a or restarting the daemon)

Test:

printf 'FROM alpine\nCMD ["echo", "hello"]' | docker buildx build . \
    -t docker.io/repo/test:latest --platform linux/amd64,linux/arm64
docker push docker.io/repo/test:latest
Test result with a fresh repo
root # docker buildx imagetools inspect docker.io/pawelgronowski465/pushworks:220824 # Repo doesn't exist1
ERROR: docker.io/pawelgronowski465/pushnotworks:220824: not found
root # cat Dockerfile
FROM alpine
CMD ["echo", "test"]
root # docker build . -t pawelgronowski465/pushworks:220824 --platform linux/arm64,linux/amd64,linux/386
[+] Building 4.4s (9/9) FINISHED
 => [internal] load .dockerignore                                                                                                         0.0s
 => => transferring context: 2B                                                                                                           0.0s
 => [internal] load build definition from Dockerfile                                                                                      0.0s
 => => transferring dockerfile: 70B                                                                                                       0.0s
 => [linux/arm64 internal] load metadata for docker.io/library/alpine:latest                                                              3.9s
 => [linux/amd64 internal] load metadata for docker.io/library/alpine:latest                                                              3.9s
 => [linux/386 internal] load metadata for docker.io/library/alpine:latest                                                                3.9s
 => [linux/amd64 1/1] FROM docker.io/library/alpine@sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad               0.0s
 => => resolve docker.io/library/alpine@sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad                           0.0s
 => [linux/386 1/1] FROM docker.io/library/alpine@sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad                 0.0s
 => => resolve docker.io/library/alpine@sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad                           0.0s
 => [linux/arm64 1/1] FROM docker.io/library/alpine@sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad               0.4s
 => => resolve docker.io/library/alpine@sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad                           0.0s
 => => sha256:9b18e9b68314027565b90ff6189d65942c0f7986da80df008b8431276885218e 0B / 2.71MB                                                0.4s
 => exporting to image                                                                                                                    0.4s
 => => exporting layers                                                                                                                   0.0s
 => => exporting manifest sha256:1e3431ac147d5ab9aad7408f9e9cf77191b909b8d5eeee4c3074d29e012a7fcf                                         0.0s
 => => exporting config sha256:03a88cfd93db02177bb2b47b7fc73504ebf75b7cc3eb4432edc01caae5535098                                           0.0s
 => => exporting manifest sha256:89aebd05109a4dba92ff76ea73b52ded8286b2c5a30467c9810eb3c6b92db91a                                         0.0s
 => => exporting config sha256:9faa6ecf5f1b46d07c961b9a490a16391a9b1f7fb30cea316dbe10992595207a                                           0.0s
 => => exporting manifest sha256:c8ed6a8c58f8e50c90be744426398f3b2fcbea51d45f0e27a266b1a69cf99d5c                                         0.0s
 => => exporting config sha256:9cff1119afd2277751867756a94fe0f20495b47374cc84d8fe7096006cdf272e                                           0.0s
 => => exporting manifest list sha256:610e37756255c286b3e3706d3239e339f4b378487c4aafe03c0941cae65ff462                                    0.0s
 => => naming to docker.io/pawelgronowski465/pushworks:220824                                                                             0.0s
 => => unpacking to docker.io/pawelgronowski465/pushworks:220824                                                                          0.4s
root # docker push docker.io/pawelgronowski465/pushworks:220824
03a88cfd93db: Pushed
9b18e9b68314: Pushed
89aebd05109a: Pushed
c8ed6a8c58f8: Pushed
610e37756255: Pushed
9cff1119afd2: Pushed
6c0d3b419d84: Pushed
213ec9aee27d: Pushed
1e3431ac147d: Pushed
9faa6ecf5f1b: Pushed
root # docker buildx imagetools inspect docker.io/pawelgronowski465/pushworks:220824
Name:      docker.io/pawelgronowski465/pushworks:220824
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:610e37756255c286b3e3706d3239e339f4b378487c4aafe03c0941cae65ff462

Manifests:
  Name:      docker.io/pawelgronowski465/pushworks:220824@sha256:1e3431ac147d5ab9aad7408f9e9cf77191b909b8d5eeee4c3074d29e012a7fcf
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

  Name:      docker.io/pawelgronowski465/pushworks:220824@sha256:89aebd05109a4dba92ff76ea73b52ded8286b2c5a30467c9810eb3c6b92db91a
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      docker.io/pawelgronowski465/pushworks:220824@sha256:c8ed6a8c58f8e50c90be744426398f3b2fcbea51d45f0e27a266b1a69cf99d5c
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/386

@vvoland vvoland force-pushed the c8d-push-lazy-blobs branch 2 times, most recently from 9541dc3 to 6282eaa Compare August 25, 2022 08:31
@vvoland vvoland marked this pull request as ready for review August 25, 2022 08:31
@vvoland
Copy link
Collaborator Author

vvoland commented Aug 25, 2022

Undrafting this as it allows the build+push case to work.
Will work on the pull+tag+push case separately.

@vvoland vvoland requested review from rumpl and thaJeztah August 25, 2022 08:32
@vvoland
Copy link
Collaborator Author

vvoland commented Aug 25, 2022

Added some comments and cleaned up the source label handling a bit.
Will squash the commits later when merging.

Copy link
Collaborator

@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.

ah, have a call, so need to continue later; submitted some nits (no blockers so far)

Comment on lines 162 to 164
// Do a small peek of the content to check if content is definitely not a json.
// Returns true when content is definitely not a json.
// If it returns false, then the content may still not be a json.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// Do a small peek of the content to check if content is definitely not a json.
// Returns true when content is definitely not a json.
// If it returns false, then the content may still not be a json.
// peekNotJson does a small peek of the content to check if content is definitely not JSON.
// It returns true if content is definitely not JSON, or false if it was unable to detect if it's
// JSON or not.

The error doesn't not appear to be described (on how it should be used in combination with the bool)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks. I didn't bother much describing the error case, as it's not really something that should happen under normal circumstances. This is called only when traversing the content store, so we expect the content to be there.
The only case of error here would be if the content is silently deleted in background between the beginning of the Walk and running handler for this particular content.
BTW, I wonder if there is some way to "lock" the store, so we can be 100% sure that this won't happen.

Copy link
Owner

Choose a reason for hiding this comment

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

I think you can use a leased context maybe?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But how do I put a lease on everything in the Content store? :P
And if I do - will lease be enough to pause something like ctr content remove <hash> until the Walk is finished?

Copy link
Owner

Choose a reason for hiding this comment

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

Yeah nah it doesn't work, the lease you add to your context is added to objects you create during that context.

Copy link
Collaborator

@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.

Left some comments, but mostly looks sane 😄

This makes it possible to push multi-platform images which contents are
missing from the local content store, but can be fetched from a source
repository.

Co-authored-by: Djordje Lukic <[email protected]>
Signed-off-by: Paweł Gronowski <[email protected]>
@vvoland vvoland force-pushed the c8d-push-lazy-blobs branch from 0720a48 to cf0b3d6 Compare August 25, 2022 16:24
Copy link
Collaborator

@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, thanks!

Let's make sure we have a tracking ticket to improve and upstream a more official approach, and discuss with the containerd maintainers.

@thaJeztah
Copy link
Collaborator

When upstreaming:

combine with one or more of;

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

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants