垃圾收集器在 Kubernetes 中的作用就是删除之前有所有者但是现在所有者已经不存在的对象,例如删除 ReplicaSet 时会删除它依赖的 Pod,虽然它的名字是垃圾收集器,但是它在 Kubernetes 中还是以控制器的形式进行设计和实现的。
在 Kubernetes 引入垃圾收集器之前,所有的级联删除逻辑都是在客户端完成的,kubectl 会先删除 ReplicaSet 持有的 Pod 再删除 ReplicaSet,但是垃圾收集器的引入就让级联删除的实现移到了服务端,我们在这里就会介绍垃圾收集器的设计和实现原理。
概述
垃圾收集主要提供的功能就是级联删除,它向对象的 API 中加入了 metadata.ownerReferences 字段,这一字段会包含当前对象的所有依赖者,在默认情况下,如果当前对象的所有依赖者都被删除,那么当前对象就会被删除:
type ObjectMeta struct {
...
OwnerReferences []OwnerReference}
type OwnerReference struct {
APIVersion string
Kind string
Name string
UID types.UID}
OwnerReference 包含了足够的信息来标识当前对象的依赖者,对象的依赖者必须与当前对象位于同一个命名空间 namespace,否则两者就无法建立起依赖关系。通过引入 metadata.ownerReferences 能够建立起不同对象的关系,但是我们依然需要其他的组件来负责处理对象之间的联系并在所有依赖者不存在时将对象删除,这个处理不同对象联系的组件就是 GarbageCollector,也是 Kubernetes 控制器的一种。
实现原理
GarbageCollector 中包含一个 GraphBuilder 结构体,这个结构体会以 Goroutine 的形式运行并使用 Informer 监听集群中几乎全部资源的变动,一旦发现任何的变更事件 — 增删改,就会将事件交给主循环处理,主循环会根据事件的不同选择将待处理对象加入不同的队列,与此同时 GarbageCollector 持有的另外两组队列会负责删除或者孤立目标对象。
接下来我们会从几个关键点介绍垃圾收集器是如何删除 Kubernetes 集群中的对象以及它们的依赖的。
删除策略
多个资源的 Informer 共同构成了垃圾收集器中的 Propagator,它监听所有的资源更新事件并将它们投入到工作队列中,这些事件会更新内存中的 DAG,这个 DAG 表示了集群中不同对象之间的从属关系,垃圾收集器的多个 Worker 会从两个队列中获取待处理的对象并调用 attemptToDeleteItem 和 attempteToOrphanItem 方法,这里我们主要介绍 attemptToDeleteItem 的实现:
func (gc *GarbageCollector) attemptToDeleteItem(item *node) error {
latest, _ :=