ownerReferences、Finalizers与garbage collector
ownerReferences
ownerReferences指明了资源的属主,即当前对象依赖于ownerReferences指向的对象。比如创建一个deployment,pod的属主为该pod对应的replicaSet(简称rs),同样这个rs也有一个属主引用,指向一个对应的deployment,以一个nginx-deployment为例,pod和rs的ownerReferences如下:
pod的ownerReferences字段
1 | metadata: |
rs的ownerReferences字段
1 | apiVersion: apps/v1 |
可以看到pod和rs各自ownerReferences对应的属主对象,pod的属主对象是rs,rs的属主对象是deployment。ownerReferences包含了属主对象的一些属性,包括apiversion、kind、uid、name等通用属性,controller字段表明属主对象是否是一个控制器,blockOwnerDeletion为true则表明删除属主对象时,会阻塞删除操作,因为有别的对象依赖它,这里删除replicaSet会阻塞,要等到它选中的pod也删除之后这个rs才会最终被删除。具体删除流程下文会具体介绍,这里先理解ownerReferences这一基本概念。
Finalizers
finalizers通常用来阻止资源的删除,其值是一个字符串slice,是依赖和被依赖对象间可以理解的一组key,当一个资源的finalizers字段不为空时,在删除该对象时,只会设置该对象的deletionTimestamp字段,代表正在删除中,只有当条件满足finalizers字段被移除,该对象才可以被最终删除。例如一个pod使用了pv,则该pv会被设置一个key为pv-protection的finalizers,表示不能直接删除这个pv,因为有pod在使用它,只有当pod不再使用该pv,这个finalizers字段才会被移除,此时这个pv才会被最终删除。
以删除configMap为例,首先创建一个包含finalizer的configMap,key为“kubernetes”。
1 | cat <<EOF | kubectl create -f - |
然后使用kubectl删除该configMap,并让其后台运行,如果没有其他任何操作,该命令会在后台一直运行,这是因为kubectl默认会等到configMap这个资源从etcd中删除后才会退出,而由于该configMap带有不为空的finalizer,所以并没有从etcd存储中删除,删除请求到kube-apiserver后,kube-apiserver只是更新了configMap的删除时间戳deletionTimestamp,可以重新get该资源来确认这一点。
1 | kubectl delete configmap/mymap & |
1 | kubectl get configmap/mymap -o yaml |
然后我们尝试更新该configMap,删除其finalizer字段
1 | kubectl patch configmap/mymap \ |
更新完后,上一步的kubectl删除操作此时才会结束退出,这虽然是一个更新操作,但到达kube-apiserver后,kube-apiserver发现该configMap的deletionTimestamp不为空即已经被标记了删除,同时更新完finalizer字段也变空,所以会直接从etcd中删除该configMap,而kubectl一直在watch等待该资源被删除,等watch到删除事件,kubectl退出,删除操作完成。
级联删除与garbage collector
级联删除cascade
在kubernetes早期版本(1.3之前),当使用kubectl删除时,级联删除的操作都在客户端完成,比如删除replicaSet,客户端先删除pod,然后再去删除replicaSet,这样导致客户端逻辑复杂,不利于扩展,之后实现了garbage collector垃圾收集器这一控制器,在server端实现级联删除的逻辑。
当使用kubectl delete删除资源时,可以设置--cascade参数指定级联删除策略,共有三种模式
background:默认策略,后台删除orphan:孤立删除foreground:前台删除
这三种策略都需要garbage collector配合完成,以删除deployment为例,三者具体区别在于:
- 使用
background删除策略时,删除deployment的请求到达kube-apiserver,deployment先被删除,然后garbage collector删除replicaSet,然删除replicaSet对应的pod; - 使用
orphan删除策略,请求到达kube-apiserver,deployment被设置deletionTimestamp标记删除,并设置key为orphan的finalizer,garbage collector移除replicaSet的ownerReferences的字段,解除deployment和replicaSet的关系,同时删除deployment的finalizer字段,然后deployment被最终删除,此时replicaSet和pod仍然存在不受影响,因此称为孤立删除,即只删除deployment,不删除对应的replicaSet和pod; - 使用
foreground删除策略,deployment被设置kube-apiserver设置key为foreground的finalizer,garbage collector发现有replicaSet依赖deployment,同时pod依赖replicaSet,于是将replicaSet同样设置key为foreground的finalizer,然后找到依赖于replicaSet的pod,使用background策略直接删除进而删除replicaSet和deployment,与background的删除策略主要不同在于先删除pod,再删除replicaSet,最后删除deployment,并通过设置finalizer控制删除顺序。
garbage collector原理
级联删除的主要逻辑都由garbage collector这一控制器来控制,garbage collector由两部分组成:graph_builder和garbagecollector。
graph_builder用来维护集群中资源的依赖拓扑图,每种资源被视为一个节点,这个节点同时存储了该节点资源对应的owner以及依赖,比例replicaSet存储了其owner deployment,同时存储了其依赖的pod,这样就可以通过每个节点直接找到其属主owner和依赖。graph_builder通过metaInformer监听集群meta数据变化,动态更新资源间的依赖关系。然后将需要删除的资源的放入队列,根据不同的删除策略orphan或者foreground分别放入不同的队列。
garbagecollector是上述两个队列的消费者,对于orphan队列里的待删除资源,主要操作为删除依赖对象的ownerReferences,使其孤立,并通过删除owner对象的finalizer使kube-apiserver删除owner对象。对于foreground队列里的待删除资源,则是不断寻找被删除资源的依赖资源,类似于递归操作,当一个最底层的对象不再被其他对象依赖时,通过指定其删除策略为background直接从存储层删除吗,对于owner对象则通过移除其值为foreground的finalizer来删除该对象。