diff --git a/builder/builder-next/adapters/containerimage/pull.go b/builder/builder-next/adapters/containerimage/pull.go index f187f5c16f..f94b4ebe9e 100644 --- a/builder/builder-next/adapters/containerimage/pull.go +++ b/builder/builder-next/adapters/containerimage/pull.go @@ -34,6 +34,7 @@ import ( "github.com/moby/buildkit/util/flightcontrol" "github.com/moby/buildkit/util/imageutil" "github.com/moby/buildkit/util/progress" + "github.com/moby/buildkit/util/resolver" "github.com/moby/buildkit/util/tracing" digest "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/identity" @@ -51,6 +52,7 @@ type SourceOpt struct { DownloadManager distribution.RootFSDownloadManager MetadataStore metadata.V2MetadataService ImageStore image.Store + ResolverOpt resolver.ResolveOptionsFunc } type imageSource struct { @@ -71,11 +73,16 @@ func (is *imageSource) ID() string { return source.DockerImageScheme } -func (is *imageSource) getResolver(ctx context.Context) remotes.Resolver { - return docker.NewResolver(docker.ResolverOptions{ +func (is *imageSource) getResolver(ctx context.Context, rfn resolver.ResolveOptionsFunc, ref string) remotes.Resolver { + opt := docker.ResolverOptions{ Client: tracing.DefaultClient, Credentials: is.getCredentialsFromSession(ctx), - }) + } + if rfn != nil { + opt = rfn(ref) + } + r := docker.NewResolver(opt) + return r } func (is *imageSource) getCredentialsFromSession(ctx context.Context) func(string) (string, string, error) { @@ -118,7 +125,7 @@ func (is *imageSource) resolveRemote(ctx context.Context, ref string, platform * dt []byte } res, err := is.g.Do(ctx, ref, func(ctx context.Context) (interface{}, error) { - dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, platform) + dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx, is.ResolverOpt, ref), is.ContentStore, platform) if err != nil { return nil, err } @@ -181,7 +188,7 @@ func (is *imageSource) Resolve(ctx context.Context, id source.Identifier) (sourc p := &puller{ src: imageIdentifier, is: is, - resolver: is.getResolver(ctx), + resolver: is.getResolver(ctx, is.ResolverOpt, imageIdentifier.Reference.String()), platform: platform, } return p, nil diff --git a/builder/builder-next/builder.go b/builder/builder-next/builder.go index 7bd93c05fc..a9792c4e7a 100644 --- a/builder/builder-next/builder.go +++ b/builder/builder-next/builder.go @@ -23,6 +23,7 @@ import ( "github.com/moby/buildkit/session" "github.com/moby/buildkit/solver/llbsolver" "github.com/moby/buildkit/util/entitlements" + "github.com/moby/buildkit/util/resolver" "github.com/moby/buildkit/util/tracing" "github.com/pkg/errors" "golang.org/x/sync/errgroup" @@ -55,6 +56,7 @@ type Opt struct { Dist images.DistributionServices NetworkController libnetwork.NetworkController DefaultCgroupParent string + ResolverOpt resolver.ResolveOptionsFunc } // Builder can build using BuildKit backend diff --git a/builder/builder-next/controller.go b/builder/builder-next/controller.go index 808b0b884f..cb9819cdd6 100644 --- a/builder/builder-next/controller.go +++ b/builder/builder-next/controller.go @@ -97,6 +97,7 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) { MetadataStore: dist.V2MetadataService, ImageStore: dist.ImageStore, ReferenceStore: dist.ReferenceStore, + ResolverOpt: opt.ResolverOpt, }) if err != nil { return nil, err @@ -160,7 +161,7 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) { WorkerController: wc, Frontends: frontends, CacheKeyStorage: cacheStorage, - ResolveCacheImporterFunc: registryremotecache.ResolveCacheImporterFunc(opt.SessionManager), + ResolveCacheImporterFunc: registryremotecache.ResolveCacheImporterFunc(opt.SessionManager, opt.ResolverOpt), // TODO: set ResolveCacheExporterFunc for exporting cache }) } diff --git a/cmd/dockerd/daemon.go b/cmd/dockerd/daemon.go index c894d2a95f..b7b902bdf6 100644 --- a/cmd/dockerd/daemon.go +++ b/cmd/dockerd/daemon.go @@ -291,6 +291,7 @@ func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, e Dist: d.DistributionServices(), NetworkController: d.NetworkController(), DefaultCgroupParent: cgroupParent, + ResolverOpt: d.NewResolveOptionsFunc(), }) if err != nil { return opts, err diff --git a/daemon/daemon.go b/daemon/daemon.go index e032a2ddda..14b31e7667 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -9,6 +9,7 @@ import ( "context" "fmt" "io/ioutil" + "math/rand" "net" "os" "path" @@ -23,6 +24,8 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/pkg/dialer" + "github.com/containerd/containerd/remotes/docker" + "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/swarm" @@ -36,6 +39,8 @@ import ( "github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/network" "github.com/docker/docker/errdefs" + "github.com/moby/buildkit/util/resolver" + "github.com/moby/buildkit/util/tracing" "github.com/sirupsen/logrus" // register graph drivers _ "github.com/docker/docker/daemon/graphdriver/register" @@ -141,6 +146,57 @@ func (daemon *Daemon) Features() *map[string]bool { return &daemon.configStore.Features } +// NewResolveOptionsFunc returns a call back function to resolve "registry-mirrors" and +// "insecure-registries" for buildkit +func (daemon *Daemon) NewResolveOptionsFunc() resolver.ResolveOptionsFunc { + return func(ref string) docker.ResolverOptions { + var ( + registryKey = "docker.io" + mirrors = make([]string, len(daemon.configStore.Mirrors)) + m = map[string]resolver.RegistryConf{} + ) + // must trim "https://" or "http://" prefix + for i, v := range daemon.configStore.Mirrors { + v = strings.TrimPrefix(v, "https://") + v = strings.TrimPrefix(v, "http://") + mirrors[i] = v + } + // set "registry-mirrors" + m[registryKey] = resolver.RegistryConf{Mirrors: mirrors} + // set "insecure-registries" + for _, v := range daemon.configStore.InsecureRegistries { + v = strings.TrimPrefix(v, "http://") + m[v] = resolver.RegistryConf{ + PlainHTTP: true, + } + } + def := docker.ResolverOptions{ + Client: tracing.DefaultClient, + } + + parsed, err := reference.ParseNormalizedNamed(ref) + if err != nil { + return def + } + host := reference.Domain(parsed) + + c, ok := m[host] + if !ok { + return def + } + + if len(c.Mirrors) > 0 { + def.Host = func(string) (string, error) { + return c.Mirrors[rand.Intn(len(c.Mirrors))], nil + } + } + + def.PlainHTTP = c.PlainHTTP + + return def + } +} + func (daemon *Daemon) restore() error { containers := make(map[string]*container.Container)