Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle image digests in node status and image GC #25088

Merged
merged 1 commit into from
May 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/kubelet/container/image_puller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestPuller(t *testing.T) {
fakeRecorder := &record.FakeRecorder{}
puller := NewImagePuller(fakeRecorder, fakeRuntime, backOff)

fakeRuntime.ImageList = []Image{{"present_image", nil, 0}}
fakeRuntime.ImageList = []Image{{"present_image", nil, nil, 1}}
fakeRuntime.Err = c.pullerErr
fakeRuntime.InspectErr = c.inspectErr

Expand Down
2 changes: 2 additions & 0 deletions pkg/kubelet/container/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ type Image struct {
ID string
// Other names by which this image is known.
RepoTags []string
// Digests by which this image is known.
RepoDigests []string
// The size of the image in bytes.
Size int64
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/kubelet/container/serialized_image_puller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestSerializedPuller(t *testing.T) {
fakeRecorder := &record.FakeRecorder{}
puller := NewSerializedImagePuller(fakeRecorder, fakeRuntime, backOff)

fakeRuntime.ImageList = []Image{{"present_image", nil, 0}}
fakeRuntime.ImageList = []Image{{"present_image", nil, nil, 0}}
fakeRuntime.Err = c.pullerErr
fakeRuntime.InspectErr = c.inspectErr

Expand Down
7 changes: 4 additions & 3 deletions pkg/kubelet/dockertools/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ func toRuntimeImage(image *dockertypes.Image) (*kubecontainer.Image, error) {
}

return &kubecontainer.Image{
ID: image.ID,
RepoTags: image.RepoTags,
Size: image.VirtualSize,
ID: image.ID,
RepoTags: image.RepoTags,
RepoDigests: image.RepoDigests,
Size: image.VirtualSize,
}, nil
}
8 changes: 5 additions & 3 deletions pkg/kubelet/dockertools/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ func TestToRuntimeImage(t *testing.T) {
original := &dockertypes.Image{
ID: "aeeea",
RepoTags: []string{"abc", "def"},
RepoDigests: []string{"123", "456"},
VirtualSize: 1234,
}
expected := &kubecontainer.Image{
ID: "aeeea",
RepoTags: []string{"abc", "def"},
Size: 1234,
ID: "aeeea",
RepoTags: []string{"abc", "def"},
RepoDigests: []string{"123", "456"},
Size: 1234,
}

actual, err := toRuntimeImage(original)
Expand Down
13 changes: 11 additions & 2 deletions pkg/kubelet/image_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ 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)
}
}
Expand All @@ -174,26 +175,31 @@ func (im *realImageManager) detectImages(detectTime time.Time) error {
im.imageRecordsLock.Lock()
defer im.imageRecordsLock.Unlock()
for _, image := range images {
glog.V(5).Infof("Adding image ID %s to currentImages", image.ID)
currentImages.Insert(image.ID)

// New image, set it as detected now.
if _, ok := im.imageRecords[image.ID]; !ok {
glog.V(5).Infof("Image ID %s is new", image.ID)
im.imageRecords[image.ID] = &imageRecord{
firstDetected: detectTime,
}
}

// Set last used time to now if the image is being used.
if isImageUsed(image, imagesInUse) {
glog.V(5).Infof("Setting Image ID %s lastUsed to %v", image.ID, now)
im.imageRecords[image.ID].lastUsed = now
}

glog.V(5).Infof("Image ID %s has size %d", image.ID, image.Size)
im.imageRecords[image.ID].size = image.Size
}

// Remove old images from our records.
for image := range im.imageRecords {
if !currentImages.Has(image) {
glog.V(5).Infof("Image ID %s is no longer present; removing from imageRecords", image)
delete(im.imageRecords, image)
}
}
Expand Down Expand Up @@ -266,15 +272,18 @@ func (im *realImageManager) freeSpace(bytesToFree int64, freeTime time.Time) (in
var lastErr error
spaceFreed := int64(0)
for _, image := range images {
glog.V(5).Infof("Evaluating image ID %s for possible garbage collection", image.id)
// Images that are currently in used were given a newer lastUsed.
if image.lastUsed.Equal(freeTime) || image.lastUsed.After(freeTime) {
glog.V(5).Infof("Image ID %s has lastUsed=%v which is >= freeTime=%v, not eligible for garbage collection", image.id, image.lastUsed, freeTime)
break
}

// Avoid garbage collect the image if the image is not old enough.
// In such a case, the image may have just been pulled down, and will be used by a container right away.

if freeTime.Sub(image.firstDetected) < im.policy.MinAge {
glog.V(5).Infof("Image ID %s has age %v which is less than the policy's minAge of %v, not eligible for garbage collection", image.id, freeTime.Sub(image.firstDetected), im.policy.MinAge)
continue
}

Expand Down Expand Up @@ -315,11 +324,11 @@ 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.
// Check the image ID and all the RepoTags and RepoDigests.
if _, ok := imagesInUse[image.ID]; ok {
return true
}
for _, tag := range image.RepoTags {
for _, tag := range append(image.RepoTags, image.RepoDigests...) {
if _, ok := imagesInUse[tag]; ok {
return true
}
Expand Down
28 changes: 28 additions & 0 deletions pkg/kubelet/image_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,34 @@ func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) {
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 = []*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,
Expand Down
2 changes: 1 addition & 1 deletion pkg/kubelet/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3009,7 +3009,7 @@ func (kl *Kubelet) setNodeStatusImages(node *api.Node) {
} else {
for _, image := range containerImages {
imagesOnNode = append(imagesOnNode, api.ContainerImage{
Names: image.RepoTags,
Names: append(image.RepoTags, image.RepoDigests...),
SizeBytes: image.Size,
})
}
Expand Down