mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	Merge pull request #29388 from ronnielai/image-gc-check
Automatic merge from submit-queue Avoiding trying to gc images with no tags which are still in use #29325
This commit is contained in:
		| @@ -95,11 +95,12 @@ func ConvertPodStatusToRunningPod(podStatus *PodStatus) Pod { | ||||
| 			continue | ||||
| 		} | ||||
| 		container := &Container{ | ||||
| 			ID:    containerStatus.ID, | ||||
| 			Name:  containerStatus.Name, | ||||
| 			Image: containerStatus.Image, | ||||
| 			Hash:  containerStatus.Hash, | ||||
| 			State: containerStatus.State, | ||||
| 			ID:      containerStatus.ID, | ||||
| 			Name:    containerStatus.Name, | ||||
| 			Image:   containerStatus.Image, | ||||
| 			ImageID: containerStatus.ImageID, | ||||
| 			Hash:    containerStatus.Hash, | ||||
| 			State:   containerStatus.State, | ||||
| 		} | ||||
| 		runningPod.Containers = append(runningPod.Containers, container) | ||||
| 	} | ||||
|   | ||||
| @@ -245,6 +245,8 @@ type Container struct { | ||||
| 	// The image name of the container, this also includes the tag of the image, | ||||
| 	// the expected form is "NAME:TAG". | ||||
| 	Image string | ||||
| 	// The id of the image used by the container. | ||||
| 	ImageID string | ||||
| 	// Hash of the container, used for comparison. Optional for containers | ||||
| 	// not managed by kubelet. | ||||
| 	Hash uint64 | ||||
|   | ||||
| @@ -56,10 +56,11 @@ func toRuntimeContainer(c *dockertypes.Container) (*kubecontainer.Container, err | ||||
| 	} | ||||
|  | ||||
| 	return &kubecontainer.Container{ | ||||
| 		ID:    kubecontainer.DockerID(c.ID).ContainerID(), | ||||
| 		Name:  dockerName.ContainerName, | ||||
| 		Image: c.Image, | ||||
| 		Hash:  hash, | ||||
| 		ID:      kubecontainer.DockerID(c.ID).ContainerID(), | ||||
| 		Name:    dockerName.ContainerName, | ||||
| 		Image:   c.Image, | ||||
| 		ImageID: c.ImageID, | ||||
| 		Hash:    hash, | ||||
| 		// (random-liu) docker uses status to indicate whether a container is running or exited. | ||||
| 		// However, in kubernetes we usually use state to indicate whether a container is running or exited, | ||||
| 		// while use status to indicate the comprehensive status of the container. So we have different naming | ||||
|   | ||||
| @@ -170,8 +170,8 @@ func (im *realImageManager) detectImages(detectTime time.Time) error { | ||||
| 	imagesInUse := sets.NewString() | ||||
| 	for _, pod := range pods { | ||||
| 		for _, container := range pod.Containers { | ||||
| 			glog.V(5).Infof("Pod %s/%s, container %s uses image %s", pod.Namespace, pod.Name, container.Name, container.Image) | ||||
| 			imagesInUse.Insert(container.Image) | ||||
| 			glog.V(5).Infof("Pod %s/%s, container %s uses image %s(%s)", pod.Namespace, pod.Name, container.Name, container.Image, container.ImageID) | ||||
| 			imagesInUse.Insert(container.ImageID) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -341,14 +341,9 @@ func (ev byLastUsedAndDetected) Less(i, j int) bool { | ||||
| } | ||||
|  | ||||
| func isImageUsed(image container.Image, imagesInUse sets.String) bool { | ||||
| 	// Check the image ID and all the RepoTags and RepoDigests. | ||||
| 	// Check the image ID. | ||||
| 	if _, ok := imagesInUse[image.ID]; ok { | ||||
| 		return true | ||||
| 	} | ||||
| 	for _, tag := range append(image.RepoTags, image.RepoDigests...) { | ||||
| 		if _, ok := imagesInUse[tag]; ok { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|   | ||||
| @@ -59,15 +59,20 @@ func (im *realImageManager) getImageRecord(name string) (*imageRecord, bool) { | ||||
| 	return &vCopy, ok | ||||
| } | ||||
|  | ||||
| // Returns the id of the image with the given ID. | ||||
| func imageID(id int) string { | ||||
| 	return fmt.Sprintf("image-%d", id) | ||||
| } | ||||
|  | ||||
| // Returns the name of the image with the given ID. | ||||
| func imageName(id int) string { | ||||
| 	return fmt.Sprintf("image-%d", id) | ||||
| 	return imageID(id) + "-name" | ||||
| } | ||||
|  | ||||
| // Make an image with the specified ID. | ||||
| func makeImage(id int, size int64) container.Image { | ||||
| 	return container.Image{ | ||||
| 		ID:   imageName(id), | ||||
| 		ID:   imageID(id), | ||||
| 		Size: size, | ||||
| 	} | ||||
| } | ||||
| @@ -75,8 +80,9 @@ func makeImage(id int, size int64) container.Image { | ||||
| // Make a container with the specified ID. It will use the image with the same ID. | ||||
| func makeContainer(id int) *container.Container { | ||||
| 	return &container.Container{ | ||||
| 		ID:    container.ContainerID{Type: "test", ID: fmt.Sprintf("container-%d", id)}, | ||||
| 		Image: imageName(id), | ||||
| 		ID:      container.ContainerID{Type: "test", ID: fmt.Sprintf("container-%d", id)}, | ||||
| 		Image:   imageName(id), | ||||
| 		ImageID: imageID(id), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -85,11 +91,21 @@ func TestDetectImagesInitialDetect(t *testing.T) { | ||||
| 	fakeRuntime.ImageList = []container.Image{ | ||||
| 		makeImage(0, 1024), | ||||
| 		makeImage(1, 2048), | ||||
| 		makeImage(2, 2048), | ||||
| 	} | ||||
| 	fakeRuntime.AllPodList = []*containertest.FakePod{ | ||||
| 		{Pod: &container.Pod{ | ||||
| 			Containers: []*container.Container{ | ||||
| 				makeContainer(1), | ||||
| 				{ | ||||
| 					ID:      container.ContainerID{Type: "test", ID: fmt.Sprintf("container-%d", 1)}, | ||||
| 					ImageID: imageID(1), | ||||
| 					// The image filed is not set to simulate a no-name image | ||||
| 				}, | ||||
| 				{ | ||||
| 					ID:      container.ContainerID{Type: "test", ID: fmt.Sprintf("container-%d", 2)}, | ||||
| 					Image:   imageName(2), | ||||
| 					ImageID: imageID(2), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}}, | ||||
| 	} | ||||
| @@ -98,12 +114,16 @@ func TestDetectImagesInitialDetect(t *testing.T) { | ||||
| 	err := manager.detectImages(zero) | ||||
| 	assert := assert.New(t) | ||||
| 	require.NoError(t, err) | ||||
| 	assert.Equal(manager.imageRecordsLen(), 2) | ||||
| 	noContainer, ok := manager.getImageRecord(imageName(0)) | ||||
| 	assert.Equal(manager.imageRecordsLen(), 3) | ||||
| 	noContainer, ok := manager.getImageRecord(imageID(0)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(zero, noContainer.firstDetected) | ||||
| 	assert.Equal(zero, noContainer.lastUsed) | ||||
| 	withContainer, ok := manager.getImageRecord(imageName(1)) | ||||
| 	withContainerUsingNoNameImage, ok := manager.getImageRecord(imageID(1)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(zero, withContainerUsingNoNameImage.firstDetected) | ||||
| 	assert.True(withContainerUsingNoNameImage.lastUsed.After(startTime)) | ||||
| 	withContainer, ok := manager.getImageRecord(imageID(2)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(zero, withContainer.firstDetected) | ||||
| 	assert.True(withContainer.lastUsed.After(startTime)) | ||||
| @@ -141,15 +161,15 @@ func TestDetectImagesWithNewImage(t *testing.T) { | ||||
| 	err = manager.detectImages(detectedTime) | ||||
| 	require.NoError(t, err) | ||||
| 	assert.Equal(manager.imageRecordsLen(), 3) | ||||
| 	noContainer, ok := manager.getImageRecord(imageName(0)) | ||||
| 	noContainer, ok := manager.getImageRecord(imageID(0)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(zero, noContainer.firstDetected) | ||||
| 	assert.Equal(zero, noContainer.lastUsed) | ||||
| 	withContainer, ok := manager.getImageRecord(imageName(1)) | ||||
| 	withContainer, ok := manager.getImageRecord(imageID(1)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(zero, withContainer.firstDetected) | ||||
| 	assert.True(withContainer.lastUsed.After(startTime)) | ||||
| 	newContainer, ok := manager.getImageRecord(imageName(2)) | ||||
| 	newContainer, ok := manager.getImageRecord(imageID(2)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(detectedTime, newContainer.firstDetected) | ||||
| 	assert.Equal(zero, noContainer.lastUsed) | ||||
| @@ -173,7 +193,7 @@ func TestDetectImagesContainerStopped(t *testing.T) { | ||||
| 	assert := assert.New(t) | ||||
| 	require.NoError(t, err) | ||||
| 	assert.Equal(manager.imageRecordsLen(), 2) | ||||
| 	withContainer, ok := manager.getImageRecord(imageName(1)) | ||||
| 	withContainer, ok := manager.getImageRecord(imageID(1)) | ||||
| 	require.True(t, ok) | ||||
|  | ||||
| 	// Simulate container being stopped. | ||||
| @@ -181,11 +201,11 @@ func TestDetectImagesContainerStopped(t *testing.T) { | ||||
| 	err = manager.detectImages(time.Now()) | ||||
| 	require.NoError(t, err) | ||||
| 	assert.Equal(manager.imageRecordsLen(), 2) | ||||
| 	container1, ok := manager.getImageRecord(imageName(0)) | ||||
| 	container1, ok := manager.getImageRecord(imageID(0)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(zero, container1.firstDetected) | ||||
| 	assert.Equal(zero, container1.lastUsed) | ||||
| 	container2, ok := manager.getImageRecord(imageName(1)) | ||||
| 	container2, ok := manager.getImageRecord(imageID(1)) | ||||
| 	require.True(t, ok) | ||||
| 	assert.Equal(zero, container2.firstDetected) | ||||
| 	assert.True(container2.lastUsed.Equal(withContainer.lastUsed)) | ||||
| @@ -331,62 +351,6 @@ func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) { | ||||
| 	assert.Len(fakeRuntime.ImageList, 1) | ||||
| } | ||||
|  | ||||
| func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) { | ||||
| 	manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{}) | ||||
| 	fakeRuntime.ImageList = []container.Image{ | ||||
| 		makeImage(0, 1024), | ||||
| 		{ | ||||
| 			ID:       "5678", | ||||
| 			RepoTags: []string{"potato", "salad"}, | ||||
| 			Size:     2048, | ||||
| 		}, | ||||
| 	} | ||||
| 	fakeRuntime.AllPodList = []*containertest.FakePod{ | ||||
| 		{Pod: &container.Pod{ | ||||
| 			Containers: []*container.Container{ | ||||
| 				{ | ||||
| 					ID:    container.ContainerID{Type: "test", ID: "c5678"}, | ||||
| 					Image: "salad", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}}, | ||||
| 	} | ||||
|  | ||||
| 	spaceFreed, err := manager.freeSpace(1024, time.Now()) | ||||
| 	assert := assert.New(t) | ||||
| 	require.NoError(t, err) | ||||
| 	assert.EqualValues(1024, spaceFreed) | ||||
| 	assert.Len(fakeRuntime.ImageList, 1) | ||||
| } | ||||
|  | ||||
| func TestFreeSpaceImagesAlsoDoesLookupByRepoDigests(t *testing.T) { | ||||
| 	manager, fakeRuntime, _ := newRealImageManager(ImageGCPolicy{}) | ||||
| 	fakeRuntime.ImageList = []container.Image{ | ||||
| 		makeImage(0, 1024), | ||||
| 		{ | ||||
| 			ID:          "5678", | ||||
| 			RepoDigests: []string{"potato", "salad"}, | ||||
| 			Size:        2048, | ||||
| 		}, | ||||
| 	} | ||||
| 	fakeRuntime.AllPodList = []*containertest.FakePod{ | ||||
| 		{Pod: &container.Pod{ | ||||
| 			Containers: []*container.Container{ | ||||
| 				{ | ||||
| 					ID:    container.ContainerID{Type: "test", ID: "c5678"}, | ||||
| 					Image: "salad", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}}, | ||||
| 	} | ||||
|  | ||||
| 	spaceFreed, err := manager.freeSpace(1024, time.Now()) | ||||
| 	assert := assert.New(t) | ||||
| 	require.NoError(t, err) | ||||
| 	assert.EqualValues(1024, spaceFreed) | ||||
| 	assert.Len(fakeRuntime.ImageList, 1) | ||||
| } | ||||
|  | ||||
| func TestGarbageCollectBelowLowThreshold(t *testing.T) { | ||||
| 	policy := ImageGCPolicy{ | ||||
| 		HighThresholdPercent: 90, | ||||
|   | ||||
| @@ -1528,9 +1528,10 @@ func (r *Runtime) convertRktPod(rktpod *rktapi.Pod) (*kubecontainer.Pod, error) | ||||
| 			ID:   buildContainerID(&containerID{rktpod.Id, app.Name}), | ||||
| 			Name: app.Name, | ||||
| 			// By default, the version returned by rkt API service will be "latest" if not specified. | ||||
| 			Image: fmt.Sprintf("%s:%s", app.Image.Name, app.Image.Version), | ||||
| 			Hash:  containerHash, | ||||
| 			State: appStateToContainerState(app.State), | ||||
| 			Image:   fmt.Sprintf("%s:%s", app.Image.Name, app.Image.Version), | ||||
| 			ImageID: app.Image.Id, | ||||
| 			Hash:    containerHash, | ||||
| 			State:   appStateToContainerState(app.State), | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -374,18 +374,20 @@ func TestGetPods(t *testing.T) { | ||||
| 					Namespace: "default", | ||||
| 					Containers: []*kubecontainer.Container{ | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), | ||||
| 							Name:  "app-1", | ||||
| 							Image: "img-name-1:latest", | ||||
| 							Hash:  1001, | ||||
| 							State: "running", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), | ||||
| 							Name:    "app-1", | ||||
| 							Image:   "img-name-1:latest", | ||||
| 							ImageID: "img-id-1", | ||||
| 							Hash:    1001, | ||||
| 							State:   "running", | ||||
| 						}, | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), | ||||
| 							Name:  "app-2", | ||||
| 							Image: "img-name-2:latest", | ||||
| 							Hash:  1002, | ||||
| 							State: "exited", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), | ||||
| 							Name:    "app-2", | ||||
| 							Image:   "img-name-2:latest", | ||||
| 							ImageID: "img-id-2", | ||||
| 							Hash:    1002, | ||||
| 							State:   "exited", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| @@ -435,18 +437,20 @@ func TestGetPods(t *testing.T) { | ||||
| 					Namespace: "default", | ||||
| 					Containers: []*kubecontainer.Container{ | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), | ||||
| 							Name:  "app-1", | ||||
| 							Image: "img-name-1:latest", | ||||
| 							Hash:  1001, | ||||
| 							State: "running", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), | ||||
| 							Name:    "app-1", | ||||
| 							Image:   "img-name-1:latest", | ||||
| 							ImageID: "img-id-1", | ||||
| 							Hash:    1001, | ||||
| 							State:   "running", | ||||
| 						}, | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), | ||||
| 							Name:  "app-2", | ||||
| 							Image: "img-name-2:latest", | ||||
| 							Hash:  1002, | ||||
| 							State: "exited", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), | ||||
| 							Name:    "app-2", | ||||
| 							Image:   "img-name-2:latest", | ||||
| 							ImageID: "img-id-2", | ||||
| 							Hash:    1002, | ||||
| 							State:   "exited", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| @@ -456,32 +460,36 @@ func TestGetPods(t *testing.T) { | ||||
| 					Namespace: "default", | ||||
| 					Containers: []*kubecontainer.Container{ | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4003:app-11"), | ||||
| 							Name:  "app-11", | ||||
| 							Image: "img-name-11:latest", | ||||
| 							Hash:  10011, | ||||
| 							State: "exited", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4003:app-11"), | ||||
| 							Name:    "app-11", | ||||
| 							Image:   "img-name-11:latest", | ||||
| 							ImageID: "img-id-11", | ||||
| 							Hash:    10011, | ||||
| 							State:   "exited", | ||||
| 						}, | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4003:app-22"), | ||||
| 							Name:  "app-22", | ||||
| 							Image: "img-name-22:latest", | ||||
| 							Hash:  10022, | ||||
| 							State: "exited", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4003:app-22"), | ||||
| 							Name:    "app-22", | ||||
| 							Image:   "img-name-22:latest", | ||||
| 							ImageID: "img-id-22", | ||||
| 							Hash:    10022, | ||||
| 							State:   "exited", | ||||
| 						}, | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4004:app-11"), | ||||
| 							Name:  "app-11", | ||||
| 							Image: "img-name-11:latest", | ||||
| 							Hash:  10011, | ||||
| 							State: "running", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4004:app-11"), | ||||
| 							Name:    "app-11", | ||||
| 							Image:   "img-name-11:latest", | ||||
| 							ImageID: "img-id-11", | ||||
| 							Hash:    10011, | ||||
| 							State:   "running", | ||||
| 						}, | ||||
| 						{ | ||||
| 							ID:    kubecontainer.BuildContainerID("rkt", "uuid-4004:app-22"), | ||||
| 							Name:  "app-22", | ||||
| 							Image: "img-name-22:latest", | ||||
| 							Hash:  10022, | ||||
| 							State: "running", | ||||
| 							ID:      kubecontainer.BuildContainerID("rkt", "uuid-4004:app-22"), | ||||
| 							Name:    "app-22", | ||||
| 							Image:   "img-name-22:latest", | ||||
| 							ImageID: "img-id-22", | ||||
| 							Hash:    10022, | ||||
| 							State:   "running", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user