k8s中,在删除deployment的时候,deployment从属的replicaset也会被删除,这背后就是垃圾收集器控制器在起作用。垃圾收集控制器中有资源对象的从属依赖关系,当某个资源对象被删除时,该资源对象的从属对象也会执行相应的删除策略。
资源对象通过引入 metadata.ownerReferences 建立起了不同对象的依赖关系。一个对象可以依赖多个,只有当所有的owner都不存在,才通过请求API server来删除。
type ObjectMeta struct {
...
OwnerReferences []OwnerReference
}
type OwnerReference struct {
APIVersion string
Kind string
Name string
UID types.UID
}
先删除附属对象,再删除属主对象
采用这种删除策略是,首先你的删除对象会进入处理中的状态,对于处于这个状态的对象,会发生一下事件:
最后,待删除对象进入这个状态后,会删除所有该对象的从对象,删除完从对象之后,删除待删除对象。此时,这个对象在API server不可见。
OwnerReference.blockOwnerDeletion=true会阻止待删除对象的删除。此时如果要删除这个对象,那必须先删除带有这个字段的从对象,才能完成删除过程。
先删除属主对象,再删除附属对象
在这个删除策略之下,API server 会立即删除这个对象,之后会在后台来清理其从对象。这个策略是kubernetes默认采用的策略。
只是简单的删除对象,不删除其从对象,剩下的对象会成为“孤儿”。
设计验证方式:通过crd定义一个garbage对象,然后garbage这个cr会创建运行nginx镜像的deployment,通过字段来分别控制是否添加ownreferences和finalizers,来达成验证目的。数据结构定义如下:
type Garbage struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec GarbageSpec `json:"spec,omitempty"`
Status GarbageStatus `json:"status,omitempty"`
}
type GarbageSpec struct {
Nginx *Nginx `json:"nginx,omitempty"`
//是否在deployment上添加ownerReference
SetOwn bool `json:"setOwn,omitempty"`
SetFinalizer SetFinalizer `json:"setFinalizer,omitempty"`
}
type Nginx struct {
Replica *int32 `json:"replica,omitempty"`
Image *string `json:"image,omitempty"`
}
type SetFinalizer struct {
//是否在garbage上添加finalizer
Set bool `json:"set,omitempty"`
//finalizer名称
Name *string `json:"name,omitempty"`
}
1.添加ownerReferences字段
apiVersion: example.bebc.com/v1
kind: Garbage
metadata:
labels:
app.kubernetes.io/name: garbage
app.kubernetes.io/instance: garbage-sample
app.kubernetes.io/part-of: garbage-collection-example
app.kuberentes.io/managed-by: kustomize
app.kubernetes.io/created-by: garbage-collection-example
name: garbage-sample
spec:
nginx:
replica: 1
image: nginx
setOwn: true
创建出来的deployment会有相应OwnerReferences字段
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2023-01-16T16:58:44Z"
generation: 1
name: garbage-sample-example
namespace: default
ownerReferences:
- apiVersion: example.bebc.com/v1
blockOwnerDeletion: true
controller: true
kind: Garbage
name: garbage-sample
uid: dd8a648b-19df-489c-aaf0-44958cb77a26
resourceVersion: "1437553"
uid: 4ff1bd6f-1427-47de-b480-97e640af2446
删除Garbage时,从属的deployment也会自动删除。
kubectl delete -f example_v1_garbage.yaml
[root@kind-master ~]# kubectl get deployments.apps garbage-sample-example
Error from server (NotFound): deployments.apps "garbage-sample-example" not found
2.不添加ownerReferences字段
apiVersion: example.bebc.com/v1
kind: Garbage
metadata:
labels:
app.kubernetes.io/name: garbage
app.kubernetes.io/instance: garbage-sample
app.kubernetes.io/part-of: garbage-collection-example
app.kuberentes.io/managed-by: kustomize
app.kubernetes.io/created-by: garbage-collection-example
name: garbage-sample
spec:
nginx:
replica: 1
image: nginx
setOwn: false
创建出的deployment并不会添加OwnerReferencs字段
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2023-01-16T22:07:59Z"
generation: 1
name: garbage-sample-example
namespace: default
resourceVersion: "1461980"
uid: 5b5c9574-6f82-4585-816c-e0885927994d
spec:
因此删除Garbage时,创建出的deployment不会自动清除。
添加finalizer字段:
apiVersion: example.bebc.com/v1
kind: Garbage
metadata:
labels:
app.kubernetes.io/name: garbage
app.kubernetes.io/instance: garbage-sample
app.kubernetes.io/part-of: garbage-collection-example
app.kuberentes.io/managed-by: kustomize
app.kubernetes.io/created-by: garbage-collection-example
name: garbage-sample
spec:
nginx:
replica: 2
image: nginx
setOwn: true
setFinalizer:
set: true
name: test
operator中控制finalizer的相应逻辑:
if garbage.DeletionTimestamp != nil {
if r.hasFinalizer(garbage) {
//删除finalizer依赖资源
err := r.deleteExternalResources(garbage)
if err != nil {
return ctrl.Result{}, fmt.Errorf("delete external resourceerr %v", err)
}
//移除相应finalizers中的字段
r.removeFinalizer(garbage)
//更新garbage对象
err = r.Update(ctx, garbage)
if err != nil {
return ctrl.Result{}, fmt.Errorf("remove finalizer and update garbage err %v", err)
}
}
return ctrl.Result{}, nil
}
//等待10s
func (r *GarbageReconciler) deleteExternalResources(obj any) error {
time.Sleep(10 * time.Second)
return nil
}
删除garbage时,需要等待10秒。
[root@kind-node garbage-collection-example]# kubectl delete -f example_v1_garbage.yaml
garbage.example.bebc.com "garbage-sample" deleted
k8s通过garbagecollector和在资源对象中设置ownerReferences和finalizers来达到控制资源对象的级联删除目的。
在garbagecollector设计文档中:https://github.com/kubernetes/design-proposals-archive/blob/main/api-machinery/garbage-collection.md
提到了级联删除从客户端移动到了服务端。个人认为,这样做有以下几个好处:
https://kubernetes.io/zh-cn/docs/concepts/architecture/garbage-collection/
https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/
https://github.com/kubernetes/design-proposals-archive/blob/main/api-machinery/garbage-collection.md
https://xie.infoq.cn/article/6a6157ff3d85e2955ebbac994
https://book.kubebuilder.io/reference/using-finalizers.html
https://zhuanlan.zhihu.com/p/519773841
https://draveness.me/kubernetes-garbage-collector/