生活处处有GC。

在使用kubernetes的时候,可能会有个疑问:用户在k8s上创建、删除了Deployment就走了,那么在node上残留的docker镜像是谁去删除的?不删除的话,日积月累,迟早耗尽node的硬盘空间。

其实k8s是有Image GC的。不知道你注意到了没有,硬盘空间紧张的时候,会发现下载到某个节点上的image会悄悄消失,其实这就是Image GC在工作。

在每个节点的kubelet配置文件/var/lib/kubelet/config.yaml

imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
imageMinimumGCAge: 2m0s

策略是这样的:

当硬盘存储使用率超过imageGCHighThresholdPercent时,会触发Image GC,直到硬盘存储使用率低于imageGCLowThresholdPercent

这里说的存储空间指的是image fs,即docker存储image的分区。

相关代码在pkg/kubelet/images/image_gc_manager.go:GarbageCollect中。

	// If over the max threshold, free enough to place us at the lower threshold.
	usagePercent := 100 - int(available*100/capacity)
	if usagePercent >= im.policy.HighThresholdPercent {
		amountToFree := capacity*int64(100-im.policy.LowThresholdPercent)/100 - available
		glog.Infof("[imageGCManager]: Disk usage on image filesystem is at %d%% which is over the high threshold (%d%%). Trying to free %d bytes", usagePercent, im.policy.HighThresholdPercent, amountToFree)
		freed, err := im.freeSpace(amountToFree, time.Now())
		if err != nil {
			return err
		}

		if freed < amountToFree {
			err := fmt.Errorf("failed to garbage collect required amount of images. Wanted to free %d bytes, but freed %d bytes", amountToFree, freed)
			im.recorder.Eventf(im.nodeRef, v1.EventTypeWarning, events.FreeDiskSpaceFailed, err.Error())
			return err
		}
    }

代码比较简单,判断空间不足则启动freeSpace,也不多free,就free到低水。

freeSpace也不复杂。思路就是从node上所有images中,剔除正在使用的image,按最后使用的时间进行排序,优先处理老image;再剔除发现的时间小于 imageMinimumGCAge 的image,之后调用cri删除该image。


Ref:

Configuring kubelet Garbage Collection