@@ -21,6 +21,7 @@ import (
2121 "encoding/json"
2222 "errors"
2323 "fmt"
24+ "net/http"
2425 "reflect"
2526
2627 "github.com/opencontainers/image-spec/identity"
@@ -38,6 +39,8 @@ import (
3839 "github.com/containerd/platforms"
3940
4041 "github.com/containerd/nerdctl/v2/pkg/api/types"
42+ "github.com/containerd/nerdctl/v2/pkg/containerdutil"
43+ "github.com/containerd/nerdctl/v2/pkg/errutil"
4144 "github.com/containerd/nerdctl/v2/pkg/healthcheck"
4245 "github.com/containerd/nerdctl/v2/pkg/idutil/imagewalker"
4346 "github.com/containerd/nerdctl/v2/pkg/imgutil/dockerconfigresolver"
@@ -131,7 +134,49 @@ func EnsureImage(ctx context.Context, client *containerd.Client, rawRef string,
131134 return nil , err
132135 }
133136
134- return PullImageWithTransfer (ctx , client , parsedReference , rawRef , options )
137+ // Transfer service is available in containerd 1.7, but full support is only in 2.0+
138+ // For containerd 1.7, use the legacy resolver-based pull method for better compatibility
139+ useTransferAPI := containerdutil .SupportsFullTransferService (ctx , client )
140+ if ! useTransferAPI {
141+ log .G (ctx ).Debug ("Detected containerd < 2.0, using legacy pull method" )
142+ }
143+
144+ if useTransferAPI {
145+ return PullImageWithTransfer (ctx , client , parsedReference , rawRef , options )
146+ }
147+
148+ var dOpts []dockerconfigresolver.Opt
149+ if options .GOptions .InsecureRegistry {
150+ log .G (ctx ).Warnf ("skipping verifying HTTPS certs for %q" , parsedReference .Domain )
151+ dOpts = append (dOpts , dockerconfigresolver .WithSkipVerifyCerts (true ))
152+ }
153+ dOpts = append (dOpts , dockerconfigresolver .WithHostsDirs (options .GOptions .HostsDir ))
154+ resolver , err := dockerconfigresolver .New (ctx , parsedReference .Domain , dOpts ... )
155+ if err != nil {
156+ return nil , err
157+ }
158+
159+ img , err := PullImage (ctx , client , resolver , parsedReference .String (), options )
160+ if err != nil {
161+ // 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".
162+ if ! errors .Is (err , http .ErrSchemeMismatch ) && ! errutil .IsErrConnectionRefused (err ) {
163+ return nil , err
164+ }
165+ if options .GOptions .InsecureRegistry {
166+ log .G (ctx ).WithError (err ).Warnf ("server %q does not seem to support HTTPS, falling back to plain HTTP" , parsedReference .Domain )
167+ dOpts = append (dOpts , dockerconfigresolver .WithPlainHTTP (true ))
168+ resolver , err = dockerconfigresolver .New (ctx , parsedReference .Domain , dOpts ... )
169+ if err != nil {
170+ return nil , err
171+ }
172+ return PullImage (ctx , client , resolver , parsedReference .String (), options )
173+ }
174+ log .G (ctx ).WithError (err ).Errorf ("server %q does not seem to support HTTPS" , parsedReference .Domain )
175+ log .G (ctx ).Info ("Hint: you may want to try --insecure-registry to allow plain HTTP (if you are in a trusted network)" )
176+ return nil , err
177+
178+ }
179+ return img , nil
135180}
136181
137182// ResolveDigest resolves `rawRef` and returns its descriptor digest.
0 commit comments