@@ -30,6 +30,8 @@ import (
3030 "github.com/containerd/containerd/reference"
3131 refdocker "github.com/containerd/containerd/reference/docker"
3232 "github.com/containerd/containerd/remotes"
33+ "github.com/containerd/containerd/remotes/docker"
34+ dockerconfig "github.com/containerd/containerd/remotes/docker/config"
3335 "github.com/containerd/nerdctl/pkg/api/types"
3436 "github.com/containerd/nerdctl/pkg/errutil"
3537 "github.com/containerd/nerdctl/pkg/imgutil/dockerconfigresolver"
@@ -117,8 +119,15 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
117119 logrus .Infof ("pushing as an eStargz image (%s, %s)" , esgzImg .Target .MediaType , esgzImg .Target .Digest )
118120 }
119121
122+ // In order to push images where most layers are the same but the
123+ // repository name is different, it is necessary to refresh the
124+ // PushTracker. Otherwise, the MANIFEST_BLOB_UNKNOWN error will occur due
125+ // to the registry not creating the corresponding layer link file,
126+ // resulting in the failure of the entire image push.
127+ pushTracker := docker .NewInMemoryTracker ()
128+
120129 pushFunc := func (r remotes.Resolver ) error {
121- return push .Push (ctx , client , r , options .Stdout , pushRef , ref , platMC , options .AllowNondistributableArtifacts , options .Quiet )
130+ return push .Push (ctx , client , r , pushTracker , options .Stdout , pushRef , ref , platMC , options .AllowNondistributableArtifacts , options .Quiet )
122131 }
123132
124133 var dOpts []dockerconfigresolver.Opt
@@ -127,10 +136,18 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
127136 dOpts = append (dOpts , dockerconfigresolver .WithSkipVerifyCerts (true ))
128137 }
129138 dOpts = append (dOpts , dockerconfigresolver .WithHostsDirs (options .GOptions .HostsDir ))
130- resolver , err := dockerconfigresolver .New (ctx , refDomain , dOpts ... )
139+
140+ ho , err := dockerconfigresolver .NewHostOptions (ctx , refDomain , dOpts ... )
131141 if err != nil {
132142 return err
133143 }
144+
145+ resolverOpts := docker.ResolverOptions {
146+ Tracker : pushTracker ,
147+ Hosts : dockerconfig .ConfigureHosts (ctx , * ho ),
148+ }
149+
150+ resolver := docker .NewResolver (resolverOpts )
134151 if err = pushFunc (resolver ); err != nil {
135152 // In some circumstance (e.g. people just use 80 port to support pure http), the error will contain message like "dial tcp <port>: connection refused"
136153 if ! errutil .IsErrHTTPResponseToHTTPSClient (err ) && ! errutil .IsErrConnectionRefused (err ) {
0 commit comments