Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable multiple exporters (alternative) #4134

Merged
merged 12 commits into from
Jan 8, 2024

Conversation

jedevc
Copy link
Member

@jedevc jedevc commented Aug 10, 2023

Some small reworks of #2760.

@a-palchikov would you be able to review this to check that this still hits the spirit of the original? The logic behind splitting this out was that while I was reviewing I found myself just endlessly nitpicking, which is quite a slow way to do review, so I thought I'd just try fixing them myself. If you're happy with the changes I've made, I'm happy to push to #2760, or try and continue the discussion in here, whichever works for you best.

Notable changes from the original include:

  • Split into separate small commits to simplify reviews.
  • Ensure client-side backwards compatibility by continuing to set the deprecated fields.
  • Moves the exporter ID into the Resolve method for the exporter (which means that even exporters of the same type are guaranteed to have unique IDs).
  • Addition of multiplexed DiffCopy using gRPC headers (similar to the existing approach for exposing containerd content stores), which allows for multiple local/tar exporters.
  • Deferring the result.MutableResult refactor (which was used primarily by frontends to avoid concurrent map-access). We can follow this up later.
  • Implement the inline cache optimization suggestion I made. This means we don't need interface juggling from the ExportImage method, while preserving the ability for exporters to request inline cache on demand (instead of requiring access through the metadata map).
  • Adds a new capability to be handled by high-level clients.
  • Adds support for multiple exporters (and image descriptors) to the build history (and fixes a possible leak, where we didn't end up freeing all the references).

Comment on lines +692 to 710
// TODO: separate these out, and return multiple exporter responses to the
// client
for _, resp := range resps {
for k, v := range resp {
if exporterResponse == nil {
exporterResponse = make(map[string]string)
}
exporterResponse[k] = v
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This is the only aspect of the overall design I'm a little unsure on. I think for now, I'd be ok this, since we already have the precedent with multiple cache exporters (see the similar comment I've added there). However, long term, I think we should split out the exporter response more (while keeping this merging behavior for the deprecated field):

message SolveResponse {
	map<string, string> ExporterResponseDeprecated = 1;

	repeated ExporterResponse ExporterResponses = 2;
	repeated ExporterCacheResponse CacheExporterResponses = 2;
	FrontendResponse FrontendRessponse = 3;
}

If we take this option, I'm happy to follow-up asap with a PR to do this, but I don't think the handling for this belongs in this one, for two reasons: 1. #2760 has already been open for more than a year and 2. we should fix this for the multiple cache exporters as well, which has already merged and been released in v0.11.

Looking through the original PR, I see notice this discussed previously: #2760 (comment). This is also a viable approach, where we could make sure that exporters didn't overwrite each other's keys - though this is potentially a non-backwards compatible change (depending on details).

@jedevc jedevc force-pushed the enable-multi-exporters branch 3 times, most recently from 949750f to 6728e37 Compare August 10, 2023 11:47
@aaronlehmann
Copy link
Collaborator

This will be very useful!

@jedevc jedevc changed the title Enable multiple exporters (testing) Enable multiple exporters (alternative) Aug 14, 2023
@jedevc jedevc marked this pull request as ready for review August 14, 2023 15:54
exporter/containerimage/writer.go Show resolved Hide resolved
session/filesync/filesync.go Outdated Show resolved Hide resolved
client/solve.go Outdated Show resolved Hide resolved
Copy link
Contributor

@a-palchikov a-palchikov left a comment

Choose a reason for hiding this comment

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

@jedevc There is no need to push to the original PR - this branch works just fine. I admit I did not quite understand some of your suggestions - reading the code made things much more clearer, thanks.

session/filesync/filesync.go Outdated Show resolved Hide resolved
solver/result/result.go Outdated Show resolved Hide resolved
solver/pb/caps.go Show resolved Hide resolved
exporter/containerimage/writer.go Outdated Show resolved Hide resolved
session/filesync/filesync.go Show resolved Hide resolved
solver/llbsolver/history.go Show resolved Hide resolved
@jedevc jedevc force-pushed the enable-multi-exporters branch 2 times, most recently from b111cb3 to deb9b41 Compare September 7, 2023 12:24
}
f, ok := sp.fs[id]
if !ok {
return errors.Errorf("exporter %q not found", id)
Copy link
Contributor

@a-palchikov a-palchikov Sep 8, 2023

Choose a reason for hiding this comment

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

This would be confusing for the user if internal ids were used (e.g. local1). Maybe use the path as ID (see below)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Given that hitting this is indicative of a buildkit internal error, I'd rather have the id printed here.

This would mean that somehow buildkit has requested to export to an exporter that the client never created.

session/filesync/filesync.go Outdated Show resolved Hide resolved
@jedevc jedevc force-pushed the enable-multi-exporters branch 2 times, most recently from 606823e to 16a74c3 Compare September 18, 2023 13:10
Copy link
Contributor

@a-palchikov a-palchikov left a comment

Choose a reason for hiding this comment

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

lgtm


require.Equal(t, resp.ExporterResponse["image.name"], target2)
require.FileExists(t, filepath.Join(destDir, "out.tar"))
require.FileExists(t, filepath.Join(destDir, "out2.tar"))
Copy link
Member

Choose a reason for hiding this comment

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

Can we validate the contents of the image and the tar?

if err != nil {
return nil, err
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Probably these lines didn't need to be moved

Copy link
Member Author

Choose a reason for hiding this comment

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

Likely not, I was just trying to match the structure of the non-map case - I can move it back if it's significant.

@jedevc
Copy link
Member Author

jedevc commented Oct 15, 2023

@tonistiigi are there any blockers on this? I'd really like to be able to close this piece out, feels like it could be a strong feature to include in v0.13.

@brunocascio
Copy link

Subscribed to this also 👍

This is useful when you have a workflows which use the image as an artifact without a registry in between but the local storage

@AkihiroSuda
Copy link
Member

Needs rebase

@AkihiroSuda
Copy link
Member

Needs rebase again

@AkihiroSuda
Copy link
Member

@jedevc Could you rebase?

jedevc and others added 11 commits January 5, 2024 12:03
Co-authored-by: fahed dorgaa <[email protected]>
Co-authored-by: a-palchikov <[email protected]>
Signed-off-by: Justin Chadwell <[email protected]>
Co-authored-by: a-palchikov <[email protected]>
Signed-off-by: Justin Chadwell <[email protected]>
This preps for the case where a single exporter source does not map
neatly onto a single inline cache - such as introducing multiple
exporters.

We also introduce laziness here - each exporter chooses to attempt
extracting the inline cache on demand, which ensures that we avoid
creating inline caches for exporters that do not support them.

Co-authored-by: a-palchikov <[email protected]>
Co-authored-by: fahed dorgaa <[email protected]>
Signed-off-by: Justin Chadwell <[email protected]>
This patch adds multi-plexing to the local file transfer protocol (from
server to client). This is implementation-wise similar to the
multiplexing from the containerd content store transfer protocol, using
a GRPC header to select the appropriate target.

Signed-off-by: Justin Chadwell <[email protected]>
Co-authored-by: a-palchikov <[email protected]>
Co-authored-by: fahed dorgaa <[email protected]>
Signed-off-by: Justin Chadwell <[email protected]>
This patch adds support for multiple exporters at the control API, and
propogates the resulting required changes through the client and the
solver.

A few notable changes:
- Each exporter instance now has an associated identifier
- Build records in the build history now have multiple possible
  descriptors to built content
- Exporter responses are all merged together (like we currently do with
  multiple cache exporters). We likely will need to revisit this design
  later, since now cache exporters do not line up one-to-one with
  exporters.

For backwards compatability, new clients will continue to produce
requests that contain the now deprecated exporter fields, as well as the
new ones. New servers will attempt to use deprecated fields if they
are present.

Co-authored-by: a-palchikov <[email protected]>
Co-authored-by: fahed dorgaa <[email protected]>
Signed-off-by: Justin Chadwell <[email protected]>
Higher-level clients should be able to check server-side caps to ensure
that when they attempt to use multiple exporters, that the feature is
actually supported.

Signed-off-by: Justin Chadwell <[email protected]>
We can derive exporter ids from their place in the exporter array in a
SolveRequest - this removes the need to manually generate and handle
multiple sets of IDs.

Signed-off-by: Justin Chadwell <[email protected]>
@jedevc
Copy link
Member Author

jedevc commented Jan 5, 2024

Rebased. Since this has an approval, once the tests pass, I'm going to merge it.

Copy link
Member

@crazy-max crazy-max 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 for the effort on this long-waiting feature!

I'm a bit worry of the exporter responses handling on client side but your suggestion in #4134 (comment) seems like a good approach as follow-up.

As discussed we could start looking at making changes in buildx (and GHA as well to deal correctly with whatever digest user wants to consume). We also already consume the master image in our e2e tests https://github.com/docker/buildx/blob/6b63e7e3de2ef20c5d7349d7b9b277d6f0a58755/.github/workflows/e2e.yml#L70 but we should do the same for the integration tests in https://github.com/docker/buildx/blob/master/.github/workflows/build.yml when running the workflow manually so we can specify a custom image.

That being said, could we make a list of tasks that should be fulfilled in #1555 for follow-ups similar to moby/moby#45897 (a new issue is fine too)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants