Преглед изворни кода

c8d/builder: Store parent in c8d image label

Images built by classic builder will have an additional label (in the
containerd image object, not image config) pointing to a parent of that
image.

This allows to differentiate intermediate images (dangling
images created as a result of a each Dockerfile instruction) from the
final images.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Paweł Gronowski пре 1 година
родитељ
комит
081b74b97d

+ 8 - 0
daemon/containerd/image_builder.go

@@ -36,6 +36,8 @@ import (
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 )
 )
 
 
+const imageLabelClassicBuilderParent = "org.mobyproject.image.parent"
+
 // GetImageAndReleasableLayer returns an image and releaseable layer for a
 // GetImageAndReleasableLayer returns an image and releaseable layer for a
 // reference or ID. Every call to GetImageAndReleasableLayer MUST call
 // reference or ID. Every call to GetImageAndReleasableLayer MUST call
 // releasableLayer.Release() to prevent leaking of layers.
 // releasableLayer.Release() to prevent leaking of layers.
@@ -392,6 +394,8 @@ func (i *ImageService) CreateImage(ctx context.Context, config []byte, parent st
 	ociImgToCreate := dockerImageToDockerOCIImage(*imgToCreate)
 	ociImgToCreate := dockerImageToDockerOCIImage(*imgToCreate)
 
 
 	var layers []ocispec.Descriptor
 	var layers []ocispec.Descriptor
+
+	var parentDigest digest.Digest
 	// if the image has a parent, we need to start with the parents layers descriptors
 	// if the image has a parent, we need to start with the parents layers descriptors
 	if parent != "" {
 	if parent != "" {
 		parentDesc, err := i.resolveDescriptor(ctx, parent)
 		parentDesc, err := i.resolveDescriptor(ctx, parent)
@@ -404,6 +408,7 @@ func (i *ImageService) CreateImage(ctx context.Context, config []byte, parent st
 		}
 		}
 
 
 		layers = parentImageManifest.Layers
 		layers = parentImageManifest.Layers
+		parentDigest = parentDesc.Digest
 	}
 	}
 
 
 	// get the info for the new layers
 	// get the info for the new layers
@@ -443,6 +448,9 @@ func (i *ImageService) CreateImage(ctx context.Context, config []byte, parent st
 		Name:      danglingImageName(commitManifestDesc.Digest),
 		Name:      danglingImageName(commitManifestDesc.Digest),
 		Target:    commitManifestDesc,
 		Target:    commitManifestDesc,
 		CreatedAt: time.Now(),
 		CreatedAt: time.Now(),
+		Labels: map[string]string{
+			imageLabelClassicBuilderParent: parentDigest.String(),
+		},
 	}
 	}
 
 
 	createdImage, err := i.client.ImageService().Update(ctx, img)
 	createdImage, err := i.client.ImageService().Update(ctx, img)

+ 3 - 0
daemon/containerd/image_commit.go

@@ -106,6 +106,9 @@ func (i *ImageService) CommitImage(ctx context.Context, cc backend.CommitConfig)
 		Name:      danglingImageName(commitManifestDesc.Digest),
 		Name:      danglingImageName(commitManifestDesc.Digest),
 		Target:    commitManifestDesc,
 		Target:    commitManifestDesc,
 		CreatedAt: time.Now(),
 		CreatedAt: time.Now(),
+		Labels: map[string]string{
+			imageLabelClassicBuilderParent: cc.ParentImageID,
+		},
 	}
 	}
 
 
 	if _, err := i.client.ImageService().Update(ctx, img); err != nil {
 	if _, err := i.client.ImageService().Update(ctx, img); err != nil {

+ 27 - 1
daemon/containerd/image_list.go

@@ -98,8 +98,34 @@ func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions)
 	contentStore := i.client.ContentStore()
 	contentStore := i.client.ContentStore()
 	uniqueImages := map[digest.Digest]images.Image{}
 	uniqueImages := map[digest.Digest]images.Image{}
 	tagsByDigest := map[digest.Digest][]string{}
 	tagsByDigest := map[digest.Digest][]string{}
+	intermediateImages := map[digest.Digest]struct{}{}
+
+	hideIntermediate := !opts.All
+	if hideIntermediate {
+		for _, img := range imgs {
+			parent, ok := img.Labels[imageLabelClassicBuilderParent]
+			if ok && parent != "" {
+				dgst, err := digest.Parse(parent)
+				if err != nil {
+					log.G(ctx).WithFields(log.Fields{
+						"error": err,
+						"value": parent,
+					}).Warnf("invalid %s label value", imageLabelClassicBuilderParent)
+				}
+				intermediateImages[dgst] = struct{}{}
+			}
+		}
+	}
 
 
 	for _, img := range imgs {
 	for _, img := range imgs {
+		isDangling := isDanglingImage(img)
+
+		if hideIntermediate && isDangling {
+			if _, ok := intermediateImages[img.Target.Digest]; ok {
+				continue
+			}
+		}
+
 		if !filter(img) {
 		if !filter(img) {
 			continue
 			continue
 		}
 		}
@@ -107,7 +133,7 @@ func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions)
 		dgst := img.Target.Digest
 		dgst := img.Target.Digest
 		uniqueImages[dgst] = img
 		uniqueImages[dgst] = img
 
 
-		if isDanglingImage(img) {
+		if isDangling {
 			continue
 			continue
 		}
 		}
 
 

+ 11 - 0
daemon/containerd/image_tag.go

@@ -73,6 +73,17 @@ func (i *ImageService) TagImage(ctx context.Context, imageID image.ID, newTag re
 		return nil
 		return nil
 	}
 	}
 
 
+	builderLabel, ok := sourceDanglingImg.Labels[imageLabelClassicBuilderParent]
+	if ok {
+		newImg.Labels = map[string]string{
+			imageLabelClassicBuilderParent: builderLabel,
+		}
+
+		if _, err := is.Update(context.Background(), newImg, "labels"); err != nil {
+			logger.WithError(err).Warnf("failed to set %s label on the newly tagged image", imageLabelClassicBuilderParent)
+		}
+	}
+
 	// Delete the source dangling image, as it's no longer dangling.
 	// Delete the source dangling image, as it's no longer dangling.
 	if err := is.Delete(context.Background(), sourceDanglingImg.Name); err != nil {
 	if err := is.Delete(context.Background(), sourceDanglingImg.Name); err != nil {
 		logger.WithError(err).Warn("unexpected error when deleting dangling image")
 		logger.WithError(err).Warn("unexpected error when deleting dangling image")