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
来删除该对象。