github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/daemon/images/service.go (about)

     1  package images // import "github.com/docker/docker/daemon/images"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/containerd/containerd/content"
     9  	"github.com/containerd/containerd/leases"
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/api/types/filters"
    12  	"github.com/docker/docker/container"
    13  	daemonevents "github.com/docker/docker/daemon/events"
    14  	"github.com/docker/docker/distribution"
    15  	"github.com/docker/docker/distribution/metadata"
    16  	"github.com/docker/docker/distribution/xfer"
    17  	"github.com/docker/docker/image"
    18  	"github.com/docker/docker/layer"
    19  	dockerreference "github.com/docker/docker/reference"
    20  	"github.com/docker/docker/registry"
    21  	"github.com/docker/libtrust"
    22  	digest "github.com/opencontainers/go-digest"
    23  	"github.com/pkg/errors"
    24  	"github.com/sirupsen/logrus"
    25  	"golang.org/x/sync/singleflight"
    26  )
    27  
    28  type containerStore interface {
    29  	// used by image delete
    30  	First(container.StoreFilter) *container.Container
    31  	// used by image prune, and image list
    32  	List() []*container.Container
    33  	// TODO: remove, only used for CommitBuildStep
    34  	Get(string) *container.Container
    35  }
    36  
    37  // ImageServiceConfig is the configuration used to create a new ImageService
    38  type ImageServiceConfig struct {
    39  	ContainerStore            containerStore
    40  	DistributionMetadataStore metadata.Store
    41  	EventsService             *daemonevents.Events
    42  	ImageStore                image.Store
    43  	LayerStore                layer.Store
    44  	MaxConcurrentDownloads    int
    45  	MaxConcurrentUploads      int
    46  	MaxDownloadAttempts       int
    47  	ReferenceStore            dockerreference.Store
    48  	RegistryService           registry.Service
    49  	TrustKey                  libtrust.PrivateKey
    50  	ContentStore              content.Store
    51  	Leases                    leases.Manager
    52  	ContentNamespace          string
    53  }
    54  
    55  // NewImageService returns a new ImageService from a configuration
    56  func NewImageService(config ImageServiceConfig) *ImageService {
    57  	logrus.Debugf("Max Concurrent Downloads: %d", config.MaxConcurrentDownloads)
    58  	logrus.Debugf("Max Concurrent Uploads: %d", config.MaxConcurrentUploads)
    59  	logrus.Debugf("Max Download Attempts: %d", config.MaxDownloadAttempts)
    60  	return &ImageService{
    61  		containers:                config.ContainerStore,
    62  		distributionMetadataStore: config.DistributionMetadataStore,
    63  		downloadManager:           xfer.NewLayerDownloadManager(config.LayerStore, config.MaxConcurrentDownloads, xfer.WithMaxDownloadAttempts(config.MaxDownloadAttempts)),
    64  		eventsService:             config.EventsService,
    65  		imageStore:                &imageStoreWithLease{Store: config.ImageStore, leases: config.Leases, ns: config.ContentNamespace},
    66  		layerStore:                config.LayerStore,
    67  		referenceStore:            config.ReferenceStore,
    68  		registryService:           config.RegistryService,
    69  		trustKey:                  config.TrustKey,
    70  		uploadManager:             xfer.NewLayerUploadManager(config.MaxConcurrentUploads),
    71  		leases:                    config.Leases,
    72  		content:                   config.ContentStore,
    73  		contentNamespace:          config.ContentNamespace,
    74  	}
    75  }
    76  
    77  // ImageService provides a backend for image management
    78  type ImageService struct {
    79  	containers                containerStore
    80  	distributionMetadataStore metadata.Store
    81  	downloadManager           *xfer.LayerDownloadManager
    82  	eventsService             *daemonevents.Events
    83  	imageStore                image.Store
    84  	layerStore                layer.Store
    85  	pruneRunning              int32
    86  	referenceStore            dockerreference.Store
    87  	registryService           registry.Service
    88  	trustKey                  libtrust.PrivateKey
    89  	uploadManager             *xfer.LayerUploadManager
    90  	leases                    leases.Manager
    91  	content                   content.Store
    92  	contentNamespace          string
    93  	usage                     singleflight.Group
    94  }
    95  
    96  // DistributionServices provides daemon image storage services
    97  type DistributionServices struct {
    98  	DownloadManager   distribution.RootFSDownloadManager
    99  	V2MetadataService metadata.V2MetadataService
   100  	LayerStore        layer.Store
   101  	ImageStore        image.Store
   102  	ReferenceStore    dockerreference.Store
   103  }
   104  
   105  // DistributionServices return services controlling daemon image storage
   106  func (i *ImageService) DistributionServices() DistributionServices {
   107  	return DistributionServices{
   108  		DownloadManager:   i.downloadManager,
   109  		V2MetadataService: metadata.NewV2MetadataService(i.distributionMetadataStore),
   110  		LayerStore:        i.layerStore,
   111  		ImageStore:        i.imageStore,
   112  		ReferenceStore:    i.referenceStore,
   113  	}
   114  }
   115  
   116  // CountImages returns the number of images stored by ImageService
   117  // called from info.go
   118  func (i *ImageService) CountImages() int {
   119  	return i.imageStore.Len()
   120  }
   121  
   122  // Children returns the children image.IDs for a parent image.
   123  // called from list.go to filter containers
   124  // TODO: refactor to expose an ancestry for image.ID?
   125  func (i *ImageService) Children(id image.ID) []image.ID {
   126  	return i.imageStore.Children(id)
   127  }
   128  
   129  // CreateLayer creates a filesystem layer for a container.
   130  // called from create.go
   131  // TODO: accept an opt struct instead of container?
   132  func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
   133  	var layerID layer.ChainID
   134  	if container.ImageID != "" {
   135  		img, err := i.imageStore.Get(container.ImageID)
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  		layerID = img.RootFS.ChainID()
   140  	}
   141  
   142  	rwLayerOpts := &layer.CreateRWLayerOpts{
   143  		MountLabel: container.MountLabel,
   144  		InitFunc:   initFunc,
   145  		StorageOpt: container.HostConfig.StorageOpt,
   146  	}
   147  
   148  	// Indexing by OS is safe here as validation of OS has already been performed in create() (the only
   149  	// caller), and guaranteed non-nil
   150  	return i.layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts)
   151  }
   152  
   153  // GetLayerByID returns a layer by ID
   154  // called from daemon.go Daemon.restore(), and Daemon.containerExport()
   155  func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
   156  	return i.layerStore.GetRWLayer(cid)
   157  }
   158  
   159  // LayerStoreStatus returns the status for each layer store
   160  // called from info.go
   161  func (i *ImageService) LayerStoreStatus() [][2]string {
   162  	return i.layerStore.DriverStatus()
   163  }
   164  
   165  // GetLayerMountID returns the mount ID for a layer
   166  // called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
   167  // TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
   168  func (i *ImageService) GetLayerMountID(cid string) (string, error) {
   169  	return i.layerStore.GetMountID(cid)
   170  }
   171  
   172  // Cleanup resources before the process is shutdown.
   173  // called from daemon.go Daemon.Shutdown()
   174  func (i *ImageService) Cleanup() {
   175  	if err := i.layerStore.Cleanup(); err != nil {
   176  		logrus.Errorf("Error during layer Store.Cleanup(): %v", err)
   177  	}
   178  }
   179  
   180  // GraphDriverName returns the name of the graph drvier
   181  // moved from Daemon.GraphDriverName, used by:
   182  // - newContainer
   183  // - to report an error in Daemon.Mount(container)
   184  func (i *ImageService) GraphDriverName() string {
   185  	return i.layerStore.DriverName()
   186  }
   187  
   188  // ReleaseLayer releases a layer allowing it to be removed
   189  // called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
   190  func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer, containerOS string) error {
   191  	metadata, err := i.layerStore.ReleaseRWLayer(rwlayer)
   192  	layer.LogReleaseMetadata(metadata)
   193  	if err != nil && !errors.Is(err, layer.ErrMountDoesNotExist) && !errors.Is(err, os.ErrNotExist) {
   194  		return errors.Wrapf(err, "driver %q failed to remove root filesystem",
   195  			i.layerStore.DriverName())
   196  	}
   197  	return nil
   198  }
   199  
   200  // LayerDiskUsage returns the number of bytes used by layer stores
   201  // called from disk_usage.go
   202  func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
   203  	ch := i.usage.DoChan("LayerDiskUsage", func() (interface{}, error) {
   204  		var allLayersSize int64
   205  		layerRefs := i.getLayerRefs()
   206  		allLayers := i.layerStore.Map()
   207  		for _, l := range allLayers {
   208  			select {
   209  			case <-ctx.Done():
   210  				return allLayersSize, ctx.Err()
   211  			default:
   212  				size, err := l.DiffSize()
   213  				if err == nil {
   214  					if _, ok := layerRefs[l.ChainID()]; ok {
   215  						allLayersSize += size
   216  					}
   217  				} else {
   218  					logrus.Warnf("failed to get diff size for layer %v", l.ChainID())
   219  				}
   220  			}
   221  		}
   222  		return allLayersSize, nil
   223  	})
   224  	select {
   225  	case <-ctx.Done():
   226  		return 0, ctx.Err()
   227  	case res := <-ch:
   228  		if res.Err != nil {
   229  			return 0, res.Err
   230  		}
   231  		return res.Val.(int64), nil
   232  	}
   233  }
   234  
   235  func (i *ImageService) getLayerRefs() map[layer.ChainID]int {
   236  	tmpImages := i.imageStore.Map()
   237  	layerRefs := map[layer.ChainID]int{}
   238  	for id, img := range tmpImages {
   239  		dgst := digest.Digest(id)
   240  		if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 {
   241  			continue
   242  		}
   243  
   244  		rootFS := *img.RootFS
   245  		rootFS.DiffIDs = nil
   246  		for _, id := range img.RootFS.DiffIDs {
   247  			rootFS.Append(id)
   248  			chid := rootFS.ChainID()
   249  			layerRefs[chid]++
   250  		}
   251  	}
   252  
   253  	return layerRefs
   254  }
   255  
   256  // ImageDiskUsage returns information about image data disk usage.
   257  func (i *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) {
   258  	ch := i.usage.DoChan("ImageDiskUsage", func() (interface{}, error) {
   259  		// Get all top images with extra attributes
   260  		images, err := i.Images(ctx, types.ImageListOptions{
   261  			Filters:        filters.NewArgs(),
   262  			SharedSize:     true,
   263  			ContainerCount: true,
   264  		})
   265  		if err != nil {
   266  			return nil, fmt.Errorf("failed to retrieve image list: %v", err)
   267  		}
   268  		return images, nil
   269  	})
   270  	select {
   271  	case <-ctx.Done():
   272  		return nil, ctx.Err()
   273  	case res := <-ch:
   274  		if res.Err != nil {
   275  			return nil, res.Err
   276  		}
   277  		return res.Val.([]*types.ImageSummary), nil
   278  	}
   279  }
   280  
   281  // UpdateConfig values
   282  //
   283  // called from reload.go
   284  func (i *ImageService) UpdateConfig(maxDownloads, maxUploads *int) {
   285  	if i.downloadManager != nil && maxDownloads != nil {
   286  		i.downloadManager.SetConcurrency(*maxDownloads)
   287  	}
   288  	if i.uploadManager != nil && maxUploads != nil {
   289  		i.uploadManager.SetConcurrency(*maxUploads)
   290  	}
   291  }