kubernetes的垃圾回收机制(资源对象删除机制)
k8s中,在删除deployment的时候,deployment从属的replicaset也会被删除,这背后就是垃圾收集器控制器在起作用
垃圾收集有什么用
概述
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
}
Kubernetes API 资源对象的删除方式
Foreground删除策略
先删除附属对象,再删除属主对象
采用这种删除策略是,首先你的删除对象会进入处理中的状态,对于处于这个状态的对象,会发生一下事件:
- API server会将这个对象中的metadata.deletionTimestamp设置上时间作为删除的标记。
- API server还会将metadata.finalizers字段写入foregroundDeletion。
- 这个对象会一直保持可见(可通过REST API访问),直到删除过程完成。
最后,待删除对象进入这个状态后,会删除所有该对象的从对象,删除完从对象之后,删除待删除对象。此时,这个对象在API server不可见。
OwnerReference.blockOwnerDeletion=true会阻止待删除对象的删除。此时如果要删除这个对象,那必须先删除带有这个字段的从对象,才能完成删除过程。
Background删除策略
先删除属主对象,再删除附属对象
在这个删除策略之下,API server 会立即删除这个对象,之后会在后台来清理其从对象。这个策略是kubernetes默认采用的策略。
Orphan删除策略
只是简单的删除对象,不删除其从对象,剩下的对象会成为“孤儿”。
通过编写Operator简单验证
验证方式
设计验证方式:通过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"`
}
验证OwnerReferences
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不会自动清除。
验证Finalizers
添加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
项目地址:https://github.com/bebc/garbage-collector-example
总结
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/
更多推荐
所有评论(0)