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 }