diff --git a/pkg/kubelet/images/image_gc_manager.go b/pkg/kubelet/images/image_gc_manager.go index c17c8741275f..831d47e789a2 100644 --- a/pkg/kubelet/images/image_gc_manager.go +++ b/pkg/kubelet/images/image_gc_manager.go @@ -89,6 +89,31 @@ type realImageGCManager struct { // Track initialization initialized bool + + // imageCache is the cache of latest image list. + imageCache imageCache +} + +// imageCache caches latest result of ListImages. +type imageCache struct { + // sync.RWMutex is the mutex protects the image cache. + sync.RWMutex + // images is the image cache. + images []kubecontainer.Image +} + +// set updates image cache. +func (i *imageCache) set(images []kubecontainer.Image) { + i.Lock() + defer i.Unlock() + i.images = images +} + +// get gets image list from image cache. +func (i *imageCache) get() []kubecontainer.Image { + i.RLock() + defer i.RUnlock() + return i.images } // Information about the images we track. @@ -142,16 +167,23 @@ func (im *realImageGCManager) Start() error { } }, 5*time.Minute, wait.NeverStop) + // Start a goroutine periodically updates image cache. + // TODO(random-liu): Merge this with the previous loop. + go wait.Until(func() { + images, err := im.runtime.ListImages() + if err != nil { + glog.Warningf("[imageGCManager] Failed to update image list: %v", err) + } else { + im.imageCache.set(images) + } + }, 30*time.Second, wait.NeverStop) + return nil } // Get a list of images on this node func (im *realImageGCManager) GetImageList() ([]kubecontainer.Image, error) { - images, err := im.runtime.ListImages() - if err != nil { - return nil, err - } - return images, nil + return im.imageCache.get(), nil } func (im *realImageGCManager) detectImages(detectTime time.Time) error { diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index f6694f581a1b..626065e7514c 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -92,6 +92,17 @@ const ( maxImgSize int64 = 1000 * 1024 * 1024 ) +// fakeImageGCManager is a fake image gc manager for testing. It will return image +// list from fake runtime directly instead of caching it. +type fakeImageGCManager struct { + fakeImageService kubecontainer.Runtime + images.ImageGCManager +} + +func (f *fakeImageGCManager) GetImageList() ([]kubecontainer.Image, error) { + return f.fakeImageService.ListImages() +} + type TestKubelet struct { kubelet *Kubelet fakeRuntime *containertest.FakeRuntime @@ -196,7 +207,12 @@ func newTestKubeletWithImageList( HighThresholdPercent: 90, LowThresholdPercent: 80, } - kubelet.imageManager, err = images.NewImageGCManager(fakeRuntime, mockCadvisor, fakeRecorder, fakeNodeRef, fakeImageGCPolicy) + imageGCManager, err := images.NewImageGCManager(fakeRuntime, mockCadvisor, fakeRecorder, fakeNodeRef, fakeImageGCPolicy) + assert.NoError(t, err) + kubelet.imageManager = &fakeImageGCManager{ + fakeImageService: fakeRuntime, + ImageGCManager: imageGCManager, + } fakeClock := clock.NewFakeClock(time.Now()) kubelet.backOff = flowcontrol.NewBackOff(time.Second, time.Minute) kubelet.backOff.Clock = fakeClock