瀏覽代碼

image/cache: Restrict cache candidates to locally built images

Restrict cache candidates only to images that were built locally.
This doesn't affect builds using `--cache-from`.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 96ac22768a8a745b1fb5e4531eaca8d2ad7327ad)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Paweł Gronowski 1 年之前
父節點
當前提交
05a370f52f
共有 1 個文件被更改,包括 54 次插入2 次删除
  1. 54 2
      image/cache/cache.go

+ 54 - 2
image/cache/cache.go

@@ -1,11 +1,13 @@
 package cache // import "github.com/docker/docker/image/cache"
 
 import (
+	"context"
 	"encoding/json"
 	"fmt"
 	"reflect"
 	"strings"
 
+	"github.com/containerd/log"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/image"
@@ -216,6 +218,22 @@ func getImageIDAndError(img *image.Image, err error) (string, error) {
 // created. nil is returned if a child cannot be found. An error is
 // returned if the parent image cannot be found.
 func getLocalCachedImage(imageStore image.Store, imgID image.ID, config *containertypes.Config) (*image.Image, error) {
+	if config == nil {
+		return nil, nil
+	}
+
+	isBuiltLocally := func(id image.ID) bool {
+		builtLocally, err := imageStore.IsBuiltLocally(id)
+		if err != nil {
+			log.G(context.TODO()).WithFields(log.Fields{
+				"error": err,
+				"id":    id,
+			}).Warn("failed to check if image was built locally")
+			return false
+		}
+		return builtLocally
+	}
+
 	// Loop on the children of the given image and check the config
 	getMatch := func(siblings []image.ID) (*image.Image, error) {
 		var match *image.Image
@@ -225,6 +243,10 @@ func getLocalCachedImage(imageStore image.Store, imgID image.ID, config *contain
 				return nil, fmt.Errorf("unable to find image %q", id)
 			}
 
+			if !isBuiltLocally(id) {
+				continue
+			}
+
 			if compare(&img.ContainerConfig, config) {
 				// check for the most up to date match
 				if img.Created != nil && (match == nil || match.Created.Before(*img.Created)) {
@@ -238,11 +260,29 @@ func getLocalCachedImage(imageStore image.Store, imgID image.ID, config *contain
 	// In this case, this is `FROM scratch`, which isn't an actual image.
 	if imgID == "" {
 		images := imageStore.Map()
+
 		var siblings []image.ID
 		for id, img := range images {
-			if img.Parent == imgID {
-				siblings = append(siblings, id)
+			if img.Parent != "" {
+				continue
+			}
+
+			if !isBuiltLocally(id) {
+				continue
 			}
+
+			// Do a quick initial filter on the Cmd to avoid adding all
+			// non-local images with empty parent to the siblings slice and
+			// performing a full config compare.
+			//
+			// config.Cmd is set to the current Dockerfile instruction so we
+			// check it against the img.ContainerConfig.Cmd which is the
+			// command of the last layer.
+			if !strSliceEqual(img.ContainerConfig.Cmd, config.Cmd) {
+				continue
+			}
+
+			siblings = append(siblings, id)
 		}
 		return getMatch(siblings)
 	}
@@ -251,3 +291,15 @@ func getLocalCachedImage(imageStore image.Store, imgID image.ID, config *contain
 	siblings := imageStore.Children(imgID)
 	return getMatch(siblings)
 }
+
+func strSliceEqual(a, b []string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i := 0; i < len(a); i++ {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}