diff --git a/pkg/kubelet/container/testing/fake_runtime.go b/pkg/kubelet/container/testing/fake_runtime.go index e9424c2c017..b6229d3a3fa 100644 --- a/pkg/kubelet/container/testing/fake_runtime.go +++ b/pkg/kubelet/container/testing/fake_runtime.go @@ -364,7 +364,13 @@ func (f *FakeRuntime) ListImages(_ context.Context) ([]kubecontainer.Image, erro defer f.Unlock() f.CalledFunctions = append(f.CalledFunctions, "ListImages") - return f.ImageList, f.Err + return snapshot(f.ImageList), f.Err +} + +func snapshot(imageList []kubecontainer.Image) []kubecontainer.Image { + result := make([]kubecontainer.Image, len(imageList)) + copy(result, imageList) + return result } func (f *FakeRuntime) RemoveImage(_ context.Context, image kubecontainer.ImageSpec) error { diff --git a/pkg/kubelet/images/image_gc_manager.go b/pkg/kubelet/images/image_gc_manager.go index 30d49fe450b..7e58b012a30 100644 --- a/pkg/kubelet/images/image_gc_manager.go +++ b/pkg/kubelet/images/image_gc_manager.go @@ -118,9 +118,6 @@ type realImageGCManager struct { // Reference to this node. nodeRef *v1.ObjectReference - // Track initialization - initialized bool - // imageCache is the cache of latest image list. imageCache imageCache @@ -196,7 +193,6 @@ func NewImageGCManager(runtime container.Runtime, statsProvider StatsProvider, r statsProvider: statsProvider, recorder: recorder, nodeRef: nodeRef, - initialized: false, tracer: tracer, } @@ -206,16 +202,9 @@ func NewImageGCManager(runtime container.Runtime, statsProvider StatsProvider, r func (im *realImageGCManager) Start() { ctx := context.Background() go wait.Until(func() { - // Initial detection make detected time "unknown" in the past. - var ts time.Time - if im.initialized { - ts = time.Now() - } - _, err := im.detectImages(ctx, ts) + _, err := im.detectImages(ctx, time.Now()) if err != nil { klog.InfoS("Failed to monitor images", "err", err) - } else { - im.initialized = true } }, 5*time.Minute, wait.NeverStop) diff --git a/pkg/kubelet/images/image_gc_manager_test.go b/pkg/kubelet/images/image_gc_manager_test.go index 3465ca8456c..4dc5816ade2 100644 --- a/pkg/kubelet/images/image_gc_manager_test.go +++ b/pkg/kubelet/images/image_gc_manager_test.go @@ -516,6 +516,41 @@ func TestDeleteUnusedImagesRemoveAllUnusedImages(t *testing.T) { assert.Len(fakeRuntime.ImageList, 1) } +func TestDeleteUnusedImagesLimitByImageLiveTime(t *testing.T) { + ctx := context.Background() + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockStatsProvider := statstest.NewMockProvider(mockCtrl) + + manager, fakeRuntime := newRealImageGCManager(ImageGCPolicy{ + MinAge: time.Second * 3, // set minAge to 3 seconds, + }, mockStatsProvider) + fakeRuntime.ImageList = []container.Image{ + makeImage(0, 1024), + makeImage(1, 2048), + makeImage(2, 2048), + } + fakeRuntime.AllPodList = []*containertest.FakePod{ + {Pod: &container.Pod{ + Containers: []*container.Container{ + makeContainer(2), + }, + }}, + } + // start to detect images + manager.Start() + // try to delete images, but images are not old enough,so no image will be deleted + err := manager.DeleteUnusedImages(ctx) + assert := assert.New(t) + require.NoError(t, err) + assert.Len(fakeRuntime.ImageList, 3) + // sleep 3 seconds, then images will be old enough to be deleted + time.Sleep(time.Second * 3) + err = manager.DeleteUnusedImages(ctx) + require.NoError(t, err) + assert.Len(fakeRuntime.ImageList, 1) +} + func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) { ctx := context.Background() mockCtrl := gomock.NewController(t)