kubernetes的垃圾回收机制(资源对象删除机制)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

垃圾收集有什么用

概述

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
提到了级联删除从客户端移动到了服务端。个人认为这样做有以下几个好处

  1. 各个控制器中不用关注删除操作逻辑只需要关注相应字段就行。
  2. 由于删除逻辑不再分散在各个控制器中因此对象的删除操作预期是可控的。

参考

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/

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: k8s