Browse Source

Create the containerd image service

Initial pull/ls works
Build is deactivated if the feature is active

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Djordje Lukic 3 năm trước cách đây
mục cha
commit
7d74269c0d

+ 32 - 33
cmd/dockerd/daemon.go

@@ -288,34 +288,39 @@ func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, e
 		return opts, err
 		return opts, err
 	}
 	}
 	cgroupParent := newCgroupParent(config)
 	cgroupParent := newCgroupParent(config)
-	bk, err := buildkit.New(buildkit.Opt{
-		SessionManager:      sm,
-		Root:                filepath.Join(config.Root, "buildkit"),
-		Dist:                d.DistributionServices(),
-		NetworkController:   d.NetworkController(),
-		DefaultCgroupParent: cgroupParent,
-		RegistryHosts:       d.RegistryHosts(),
-		BuilderConfig:       config.Builder,
-		Rootless:            d.Rootless(),
-		IdentityMapping:     d.IdentityMapping(),
-		DNSConfig:           config.DNSConfig,
-		ApparmorProfile:     daemon.DefaultApparmorProfile(),
-	})
-	if err != nil {
-		return opts, err
-	}
-
-	bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk, d.EventsService)
-	if err != nil {
-		return opts, errors.Wrap(err, "failed to create buildmanager")
-	}
-	return routerOptions{
+	ro := routerOptions{
 		sessionManager: sm,
 		sessionManager: sm,
-		buildBackend:   bb,
-		buildkit:       bk,
 		features:       d.Features(),
 		features:       d.Features(),
 		daemon:         d,
 		daemon:         d,
-	}, nil
+	}
+	if !d.UsesSnapshotter() {
+		bk, err := buildkit.New(buildkit.Opt{
+			SessionManager:      sm,
+			Root:                filepath.Join(config.Root, "buildkit"),
+			Dist:                d.DistributionServices(),
+			NetworkController:   d.NetworkController(),
+			DefaultCgroupParent: cgroupParent,
+			RegistryHosts:       d.RegistryHosts(),
+			BuilderConfig:       config.Builder,
+			Rootless:            d.Rootless(),
+			IdentityMapping:     d.IdentityMapping(),
+			DNSConfig:           config.DNSConfig,
+			ApparmorProfile:     daemon.DefaultApparmorProfile(),
+		})
+		if err != nil {
+			return opts, err
+		}
+
+		bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk, d.EventsService)
+		if err != nil {
+			return opts, errors.Wrap(err, "failed to create buildmanager")
+		}
+
+		ro.buildBackend = bb
+		ro.buildkit = bk
+	}
+
+	return ro, nil
 }
 }
 
 
 func (cli *DaemonCli) reloadConfig() {
 func (cli *DaemonCli) reloadConfig() {
@@ -536,14 +541,8 @@ func initRouter(opts routerOptions) {
 		distributionrouter.NewRouter(opts.daemon.ImageService()),
 		distributionrouter.NewRouter(opts.daemon.ImageService()),
 	}
 	}
 
 
-	grpcBackends := []grpcrouter.Backend{}
-	for _, b := range []interface{}{opts.daemon, opts.buildBackend} {
-		if b, ok := b.(grpcrouter.Backend); ok {
-			grpcBackends = append(grpcBackends, b)
-		}
-	}
-	if len(grpcBackends) > 0 {
-		routers = append(routers, grpcrouter.NewRouter(grpcBackends...))
+	if opts.buildBackend != nil {
+		routers = append(routers, grpcrouter.NewRouter(opts.buildBackend))
 	}
 	}
 
 
 	if opts.daemon.NetworkControllerEnabled() {
 	if opts.daemon.NetworkControllerEnabled() {

+ 370 - 0
daemon/containerd/service.go

@@ -0,0 +1,370 @@
+package containerd
+
+import (
+	"context"
+	"io"
+
+	"github.com/containerd/containerd"
+	"github.com/containerd/containerd/platforms"
+	"github.com/docker/distribution"
+	"github.com/docker/distribution/reference"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/backend"
+	"github.com/docker/docker/api/types/filters"
+	imagetype "github.com/docker/docker/api/types/image"
+	registrytypes "github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/builder"
+	"github.com/docker/docker/container"
+	"github.com/docker/docker/daemon/images"
+	"github.com/docker/docker/errdefs"
+	"github.com/docker/docker/image"
+	"github.com/docker/docker/layer"
+	"github.com/opencontainers/go-digest"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageService implements daemon.ImageService
+type ImageService struct {
+	client *containerd.Client
+}
+
+// NewService creates a new ImageService.
+func NewService(c *containerd.Client) *ImageService {
+	return &ImageService{
+		client: c,
+	}
+}
+
+// PullImage initiates a pull operation. image is the repository name to pull, and
+// tagOrDigest may be either empty, or indicate a specific tag or digest to pull.
+func (cs *ImageService) PullImage(ctx context.Context, image, tagOrDigest string, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+	var opts []containerd.RemoteOpt
+	if platform != nil {
+		opts = append(opts, containerd.WithPlatform(platforms.Format(*platform)))
+	}
+	ref, err := reference.ParseNormalizedNamed(image)
+	if err != nil {
+		return errdefs.InvalidParameter(err)
+	}
+
+	// TODO(thaJeztah) this could use a WithTagOrDigest() utility
+	if tagOrDigest != "" {
+		// The "tag" could actually be a digest.
+		var dgst digest.Digest
+		dgst, err = digest.Parse(tagOrDigest)
+		if err == nil {
+			ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst)
+		} else {
+			ref, err = reference.WithTag(ref, tagOrDigest)
+		}
+		if err != nil {
+			return errdefs.InvalidParameter(err)
+		}
+	}
+
+	_, err = cs.client.Pull(ctx, ref.String(), opts...)
+	return err
+}
+
+// Images returns a filtered list of images.
+func (cs *ImageService) Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) {
+	imgs, err := cs.client.ListImages(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	var ret []*types.ImageSummary
+	for _, img := range imgs {
+		size, err := img.Size(ctx)
+		if err != nil {
+			return nil, err
+		}
+
+		ret = append(ret, &types.ImageSummary{
+			RepoDigests: []string{img.Name() + "@" + img.Target().Digest.String()}, // "hello-world@sha256:bfea6278a0a267fad2634554f4f0c6f31981eea41c553fdf5a83e95a41d40c38"},
+			RepoTags:    []string{img.Name()},
+			Containers:  -1,
+			ParentID:    "",
+			SharedSize:  -1,
+			VirtualSize: 10,
+			ID:          img.Target().Digest.String(),
+			Created:     img.Metadata().CreatedAt.Unix(),
+			Size:        size,
+		})
+	}
+
+	return ret, nil
+}
+
+// LogImageEvent generates an event related to an image with only the
+// default attributes.
+func (cs *ImageService) LogImageEvent(imageID, refName, action string) {
+	panic("not implemented")
+}
+
+// LogImageEventWithAttributes generates an event related to an image with
+// specific given attributes.
+func (cs *ImageService) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
+	panic("not implemented")
+}
+
+// GetLayerFolders returns the layer folders from an image RootFS.
+func (cs *ImageService) GetLayerFolders(img *image.Image, rwLayer layer.RWLayer) ([]string, error) {
+	panic("not implemented")
+}
+
+// Map returns a map of all images in the ImageStore.
+func (cs *ImageService) Map() map[image.ID]*image.Image {
+	panic("not implemented")
+}
+
+// GetLayerByID returns a layer by ID
+// called from daemon.go Daemon.restore(), and Daemon.containerExport().
+func (cs *ImageService) GetLayerByID(string) (layer.RWLayer, error) {
+	panic("not implemented")
+}
+
+// GetLayerMountID returns the mount ID for a layer
+// called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
+// TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
+func (cs *ImageService) GetLayerMountID(string) (string, error) {
+	panic("not implemented")
+}
+
+// Cleanup resources before the process is shutdown.
+// called from daemon.go Daemon.Shutdown()
+func (cs *ImageService) Cleanup() error {
+	return nil
+}
+
+// GraphDriverName returns the name of the graph drvier
+// moved from Daemon.GraphDriverName, used by:
+// - newContainer
+// - to report an error in Daemon.Mount(container)
+func (cs *ImageService) GraphDriverName() string {
+	return ""
+}
+
+// CommitBuildStep is used by the builder to create an image for each step in
+// the build.
+//
+// This method is different from CreateImageFromContainer:
+//   - it doesn't attempt to validate container state
+//   - it doesn't send a commit action to metrics
+//   - it doesn't log a container commit event
+//
+// This is a temporary shim. Should be removed when builder stops using commit.
+func (cs *ImageService) CommitBuildStep(c backend.CommitConfig) (image.ID, error) {
+	panic("not implemented")
+}
+
+// CreateImage creates a new image by adding a config and ID to the image store.
+// This is similar to LoadImage() except that it receives JSON encoded bytes of
+// an image instead of a tar archive.
+func (cs *ImageService) CreateImage(config []byte, parent string) (builder.Image, error) {
+	panic("not implemented")
+}
+
+// GetImageAndReleasableLayer returns an image and releaseable layer for a
+// eference or ID. Every call to GetImageAndReleasableLayer MUST call
+// releasableLayer.Release() to prevent leaking of layers.
+func (cs *ImageService) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error) {
+	panic("not implemented")
+}
+
+// MakeImageCache creates a stateful image cache.
+func (cs *ImageService) MakeImageCache(sourceRefs []string) builder.ImageCache {
+	panic("not implemented")
+}
+
+// TagImageWithReference adds the given reference to the image ID provided.
+func (cs *ImageService) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
+	panic("not implemented")
+}
+
+// SquashImage creates a new image with the diff of the specified image and
+// the specified parent. This new image contains only the layers from its
+// parent + 1 extra layer which contains the diff of all the layers in between.
+// The existing image(s) is not destroyed. If no parent is specified, a new
+// image with the diff of all the specified image's layers merged into a new
+// layer that has no parents.
+func (cs *ImageService) SquashImage(id, parent string) (string, error) {
+	panic("not implemented")
+}
+
+// ExportImage exports a list of images to the given output stream. The
+// exported images are archived into a tar when written to the output
+// stream. All images with the given tag and all versions containing
+// the same tag are exported. names is the set of tags to export, and
+// outStream is the writer which the images are written to.
+func (cs *ImageService) ExportImage(names []string, outStream io.Writer) error {
+	panic("not implemented")
+}
+
+// ImageDelete deletes the image referenced by the given imageRef from this
+// daemon. The given imageRef can be an image ID, ID prefix, or a repository
+// reference (with an optional tag or digest, defaulting to the tag name
+// "latest"). There is differing behavior depending on whether the given
+// imageRef is a repository reference or not.
+//
+// If the given imageRef is a repository reference then that repository
+// reference will be removed. However, if there exists any containers which
+// were created using the same image reference then the repository reference
+// cannot be removed unless either there are other repository references to the
+// same image or force is true. Following removal of the repository reference,
+// the referenced image itself will attempt to be deleted as described below
+// but quietly, meaning any image delete conflicts will cause the image to not
+// be deleted and the conflict will not be reported.
+//
+// There may be conflicts preventing deletion of an image and these conflicts
+// are divided into two categories grouped by their severity:
+//
+// Hard Conflict:
+//   - a pull or build using the image.
+//   - any descendant image.
+//   - any running container using the image.
+//
+// Soft Conflict:
+//   - any stopped container using the image.
+//   - any repository tag or digest references to the image.
+//
+// The image cannot be removed if there are any hard conflicts and can be
+// removed if there are soft conflicts only if force is true.
+//
+// If prune is true, ancestor images will each attempt to be deleted quietly,
+// meaning any delete conflicts will cause the image to not be deleted and the
+// conflict will not be reported.
+func (cs *ImageService) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) {
+	panic("not implemented")
+}
+
+// ImageHistory returns a slice of ImageHistory structures for the specified
+// image name by walking the image lineage.
+func (cs *ImageService) ImageHistory(name string) ([]*imagetype.HistoryResponseItem, error) {
+	panic("not implemented")
+}
+
+// ImagesPrune removes unused images
+func (cs *ImageService) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
+	panic("not implemented")
+}
+
+// ImportImage imports an image, getting the archived layer data either from
+// inConfig (if src is "-"), or from a URI specified in src. Progress output is
+// written to outStream. Repository and tag names can optionally be given in
+// the repo and tag arguments, respectively.
+func (cs *ImageService) ImportImage(src string, repository string, platform *ocispec.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
+	panic("not implemented")
+}
+
+// LoadImage uploads a set of images into the repository. This is the
+// complement of ExportImage.  The input stream is an uncompressed tar
+// ball containing images and metadata.
+func (cs *ImageService) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
+	panic("not implemented")
+}
+
+// LookupImage is not implemented.
+func (cs *ImageService) LookupImage(ctx context.Context, name string) (*types.ImageInspect, error) {
+	panic("not implemented")
+}
+
+// PushImage initiates a push operation on the repository named localName.
+func (cs *ImageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+	panic("not implemented")
+}
+
+// SearchRegistryForImages queries the registry for images matching
+// term. authConfig is used to login.
+//
+// TODO: this could be implemented in a registry service instead of the image
+// service.
+func (cs *ImageService) SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registrytypes.SearchResults, error) {
+	panic("not implemented")
+}
+
+// TagImage creates the tag specified by newTag, pointing to the image named
+// imageName (alternatively, imageName can also be an image ID).
+func (cs *ImageService) TagImage(imageName, repository, tag string) (string, error) {
+	panic("not implemented")
+}
+
+// GetRepository returns a repository from the registry.
+func (cs *ImageService) GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, error) {
+	panic("not implemented")
+}
+
+// ImageDiskUsage returns information about image data disk usage.
+func (cs *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) {
+	panic("not implemented")
+}
+
+// LayerDiskUsage returns the number of bytes used by layer stores
+// called from disk_usage.go
+func (cs *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
+	panic("not implemented")
+}
+
+// ReleaseLayer releases a layer allowing it to be removed
+// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
+func (cs *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
+	panic("not implemented")
+}
+
+// CommitImage creates a new image from a commit config.
+func (cs *ImageService) CommitImage(c backend.CommitConfig) (image.ID, error) {
+	panic("not implemented")
+}
+
+// GetImage returns an image corresponding to the image referred to by refOrID.
+func (cs *ImageService) GetImage(refOrID string, platform *ocispec.Platform) (retImg *image.Image, retErr error) {
+	panic("not implemented")
+}
+
+// CreateLayer creates a filesystem layer for a container.
+// called from create.go
+// TODO: accept an opt struct instead of container?
+func (cs *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
+	panic("not implemented")
+}
+
+// DistributionServices return services controlling daemon image storage.
+func (cs *ImageService) DistributionServices() images.DistributionServices {
+	return images.DistributionServices{}
+}
+
+// CountImages returns the number of images stored by ImageService
+// called from info.go
+func (cs *ImageService) CountImages() int {
+	imgs, err := cs.client.ListImages(context.TODO())
+	if err != nil {
+		return 0
+	}
+
+	return len(imgs)
+}
+
+// LayerStoreStatus returns the status for each layer store
+// called from info.go
+func (cs *ImageService) LayerStoreStatus() [][2]string {
+	return [][2]string{}
+}
+
+// GetContainerLayerSize returns the real size & virtual size of the container.
+func (cs *ImageService) GetContainerLayerSize(containerID string) (int64, int64) {
+	panic("not implemented")
+}
+
+// UpdateConfig values
+//
+// called from reload.go
+func (cs *ImageService) UpdateConfig(maxDownloads, maxUploads int) {
+	panic("not implemented")
+}
+
+// Children returns the children image.IDs for a parent image.
+// called from list.go to filter containers
+// TODO: refactor to expose an ancestry for image.ID?
+func (cs *ImageService) Children(id image.ID) []image.ID {
+	panic("not implemented")
+}

+ 62 - 55
daemon/daemon.go

@@ -28,6 +28,7 @@ import (
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/daemon/config"
+	ctrd "github.com/docker/docker/daemon/containerd"
 	"github.com/docker/docker/daemon/events"
 	"github.com/docker/docker/daemon/events"
 	"github.com/docker/docker/daemon/exec"
 	"github.com/docker/docker/daemon/exec"
 	_ "github.com/docker/docker/daemon/graphdriver/register" // register graph drivers
 	_ "github.com/docker/docker/daemon/graphdriver/register" // register graph drivers
@@ -141,8 +142,8 @@ func (daemon *Daemon) Features() *map[string]bool {
 	return &daemon.configStore.Features
 	return &daemon.configStore.Features
 }
 }
 
 
-// usesSnapshotter returns true if feature flag to use containerd snapshotter is enabled
-func (daemon *Daemon) usesSnapshotter() bool {
+// UsesSnapshotter returns true if feature flag to use containerd snapshotter is enabled
+func (daemon *Daemon) UsesSnapshotter() bool {
 	if daemon.configStore.Features != nil {
 	if daemon.configStore.Features != nil {
 		if b, ok := daemon.configStore.Features["containerd-snapshotter"]; ok {
 		if b, ok := daemon.configStore.Features["containerd-snapshotter"]; ok {
 			return b
 			return b
@@ -964,15 +965,6 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
 	}
 	}
 
 
 	imageRoot := filepath.Join(config.Root, "image", d.graphDriver)
 	imageRoot := filepath.Join(config.Root, "image", d.graphDriver)
-	ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
-	if err != nil {
-		return nil, err
-	}
-
-	imageStore, err := image.NewImageStore(ifs, layerStore)
-	if err != nil {
-		return nil, err
-	}
 
 
 	d.volumes, err = volumesservice.NewVolumeService(config.Root, d.PluginStore, rootIDs, d)
 	d.volumes, err = volumesservice.NewVolumeService(config.Root, d.PluginStore, rootIDs, d)
 	if err != nil {
 	if err != nil {
@@ -1004,11 +996,6 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
 	}
 	}
 	d.ReferenceStore = rs
 	d.ReferenceStore = rs
 
 
-	distributionMetadataStore, err := dmetadata.NewFSMetadataStore(filepath.Join(imageRoot, "distribution"))
-	if err != nil {
-		return nil, err
-	}
-
 	// Check if Devices cgroup is mounted, it is hard requirement for container security,
 	// Check if Devices cgroup is mounted, it is hard requirement for container security,
 	// on Linux.
 	// on Linux.
 	//
 	//
@@ -1039,55 +1026,75 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
 
 
 	d.linkIndex = newLinkIndex()
 	d.linkIndex = newLinkIndex()
 
 
-	imgSvcConfig := images.ImageServiceConfig{
-		ContainerStore:            d.containers,
-		DistributionMetadataStore: distributionMetadataStore,
-		EventsService:             d.EventsService,
-		ImageStore:                imageStore,
-		LayerStore:                layerStore,
-		MaxConcurrentDownloads:    config.MaxConcurrentDownloads,
-		MaxConcurrentUploads:      config.MaxConcurrentUploads,
-		MaxDownloadAttempts:       config.MaxDownloadAttempts,
-		ReferenceStore:            rs,
-		RegistryService:           registryService,
-		ContentNamespace:          config.ContainerdNamespace,
-	}
-
-	// This is a temporary environment variables used in CI to allow pushing
-	// manifest v2 schema 1 images to test-registries used for testing *pulling*
-	// these images.
-	if os.Getenv("DOCKER_ALLOW_SCHEMA1_PUSH_DONOTUSE") != "" {
-		imgSvcConfig.TrustKey, err = loadOrCreateTrustKey(config.TrustKeyPath)
+	if d.UsesSnapshotter() {
+		d.imageService = ctrd.NewService(d.containerdCli)
+	} else {
+		ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		if err = system.MkdirAll(filepath.Join(config.Root, "trust"), 0700); err != nil {
+
+		imageStore, err := image.NewImageStore(ifs, layerStore)
+		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-	}
 
 
-	// containerd is not currently supported with Windows.
-	// So sometimes d.containerdCli will be nil
-	// In that case we'll create a local content store... but otherwise we'll use containerd
-	if d.containerdCli != nil {
-		imgSvcConfig.Leases = d.containerdCli.LeasesService()
-		imgSvcConfig.ContentStore = d.containerdCli.ContentStore()
-	} else {
-		cs, lm, err := d.configureLocalContentStore()
+		distributionMetadataStore, err := dmetadata.NewFSMetadataStore(filepath.Join(imageRoot, "distribution"))
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		imgSvcConfig.ContentStore = cs
-		imgSvcConfig.Leases = lm
-	}
 
 
-	// TODO: imageStore, distributionMetadataStore, and ReferenceStore are only
-	// used above to run migration. They could be initialized in ImageService
-	// if migration is called from daemon/images. layerStore might move as well.
-	d.imageService = images.NewImageService(imgSvcConfig)
-	logrus.Debugf("Max Concurrent Downloads: %d", imgSvcConfig.MaxConcurrentDownloads)
-	logrus.Debugf("Max Concurrent Uploads: %d", imgSvcConfig.MaxConcurrentUploads)
-	logrus.Debugf("Max Download Attempts: %d", imgSvcConfig.MaxDownloadAttempts)
+		imgSvcConfig := images.ImageServiceConfig{
+			ContainerStore:            d.containers,
+			DistributionMetadataStore: distributionMetadataStore,
+			EventsService:             d.EventsService,
+			ImageStore:                imageStore,
+			LayerStore:                layerStore,
+			MaxConcurrentDownloads:    config.MaxConcurrentDownloads,
+			MaxConcurrentUploads:      config.MaxConcurrentUploads,
+			MaxDownloadAttempts:       config.MaxDownloadAttempts,
+			ReferenceStore:            rs,
+			RegistryService:           registryService,
+			ContentNamespace:          config.ContainerdNamespace,
+		}
+
+		// This is a temporary environment variables used in CI to allow pushing
+		// manifest v2 schema 1 images to test-registries used for testing *pulling*
+		// these images.
+		if os.Getenv("DOCKER_ALLOW_SCHEMA1_PUSH_DONOTUSE") != "" {
+			imgSvcConfig.TrustKey, err = loadOrCreateTrustKey(config.TrustKeyPath)
+			if err != nil {
+				return nil, err
+			}
+			if err = system.MkdirAll(filepath.Join(config.Root, "trust"), 0700); err != nil {
+				return nil, err
+			}
+		}
+
+		// containerd is not currently supported with Windows.
+		// So sometimes d.containerdCli will be nil
+		// In that case we'll create a local content store... but otherwise we'll use containerd
+		if d.containerdCli != nil {
+			imgSvcConfig.Leases = d.containerdCli.LeasesService()
+			imgSvcConfig.ContentStore = d.containerdCli.ContentStore()
+		} else {
+			cs, lm, err := d.configureLocalContentStore()
+			if err != nil {
+				return nil, err
+			}
+			imgSvcConfig.ContentStore = cs
+			imgSvcConfig.Leases = lm
+		}
+
+		// TODO: imageStore, distributionMetadataStore, and ReferenceStore are only
+		// used above to run migration. They could be initialized in ImageService
+		// if migration is called from daemon/images. layerStore might move as well.
+		d.imageService = images.NewImageService(imgSvcConfig)
+
+		logrus.Debugf("Max Concurrent Downloads: %d", imgSvcConfig.MaxConcurrentDownloads)
+		logrus.Debugf("Max Concurrent Uploads: %d", imgSvcConfig.MaxConcurrentUploads)
+		logrus.Debugf("Max Download Attempts: %d", imgSvcConfig.MaxDownloadAttempts)
+	}
 
 
 	go d.execCommandGC()
 	go d.execCommandGC()
 
 

+ 2 - 2
daemon/oci_linux.go

@@ -720,14 +720,14 @@ func sysctlExists(s string) bool {
 // WithCommonOptions sets common docker options
 // WithCommonOptions sets common docker options
 func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
 func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
 	return func(ctx context.Context, _ coci.Client, _ *containers.Container, s *coci.Spec) error {
 	return func(ctx context.Context, _ coci.Client, _ *containers.Container, s *coci.Spec) error {
-		if c.BaseFS == nil && !daemon.usesSnapshotter() {
+		if c.BaseFS == nil && !daemon.UsesSnapshotter() {
 			return errors.New("populateCommonSpec: BaseFS of container " + c.ID + " is unexpectedly nil")
 			return errors.New("populateCommonSpec: BaseFS of container " + c.ID + " is unexpectedly nil")
 		}
 		}
 		linkedEnv, err := daemon.setupLinkedContainers(c)
 		linkedEnv, err := daemon.setupLinkedContainers(c)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		if !daemon.usesSnapshotter() {
+		if !daemon.UsesSnapshotter() {
 			s.Root = &specs.Root{
 			s.Root = &specs.Root{
 				Path:     c.BaseFS.Path(),
 				Path:     c.BaseFS.Path(),
 				Readonly: c.HostConfig.ReadonlyRootfs,
 				Readonly: c.HostConfig.ReadonlyRootfs,