天天看點

kubernetes的垃圾回收機制(資源對象删除機制)垃圾收集有什麼用Kubernetes API 資源對象的删除方式通過編寫Operator簡單驗證總結參考

垃圾收集有什麼用

概述

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 
           
[[email protected] ~]# 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秒。

[[email protected] 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/