From e9804322f82513ea1c8590be5cca4559a2bc571f Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 11 Nov 2025 10:43:54 -0800 Subject: [PATCH] imagetools: fix concurrent map write from containerd issue Workaround for containerd issue that can cause concurrent map write when WithMediaTypeKeyPrefix is called in parallel goroutines for context that originated from same base context. Signed-off-by: Tonis Tiigi --- commands/imagetools/create.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/commands/imagetools/create.go b/commands/imagetools/create.go index 4aaef130d..95c59f0d8 100644 --- a/commands/imagetools/create.go +++ b/commands/imagetools/create.go @@ -168,11 +168,6 @@ func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, arg return errors.Wrapf(err, "failed to parse annotations") } - ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.oci.empty.v1+json", "empty") - ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.dev.cosign.artifact.sig.v1+json", "cosign") - ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.dev.cosign.simplesigning.v1+json", "simplesigning") - ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.dev.sigstore.bundle.v0.3+json", "sigstore-bundle") - dt, desc, manifests, err := r.Combine(ctx, srcs, annotations, in.preferIndex, platforms) if err != nil { return err @@ -208,9 +203,11 @@ func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, arg for _, t := range tags { eg.Go(func() error { return progress.Wrap(fmt.Sprintf("pushing %s", t.String()), pw.Write, func(sub progress.SubLogger) error { + baseCtx := ctx eg2, _ := errgroup.WithContext(ctx) for _, desc := range manifests { eg2.Go(func() error { + ctx = withMediaTypeKeyPrefix(baseCtx) sub.Log(1, fmt.Appendf(nil, "copying %s from %s to %s\n", desc.Digest.String(), desc.Source.Ref.String(), t.String())) return r.Copy(ctx, desc.Source, t) }) @@ -218,6 +215,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, arg if err := eg2.Wait(); err != nil { return err } + ctx = withMediaTypeKeyPrefix(ctx) // because of containerd bug this needs to be called separately for each ctx/goroutine pair to avoid concurrent map write sub.Log(1, fmt.Appendf(nil, "pushing %s to %s\n", desc.Digest.String(), t.String())) return r.Push(ctx, t, desc, dt) }) @@ -265,6 +263,14 @@ func parsePlatforms(in []string) ([]ocispecs.Platform, error) { return out, nil } +func withMediaTypeKeyPrefix(ctx context.Context) context.Context { + ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.oci.empty.v1+json", "empty") + ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.dev.cosign.artifact.sig.v1+json", "cosign") + ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.dev.cosign.simplesigning.v1+json", "simplesigning") + ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.dev.sigstore.bundle.v0.3+json", "sigstore-bundle") + return ctx +} + func parseRefs(in []string) ([]reference.Named, error) { refs := make([]reference.Named, len(in)) for i, in := range in {