垃圾收集有什麼用
概述
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
提到了級聯删除從用戶端移動到了服務端。個人認為,這樣做有以下幾個好處:
- 各個控制器中不用關注删除操作邏輯,隻需要關注相應字段就行。
- 由于删除邏輯不再分散在各個控制器中,是以對象的删除操作預期是可控的。
參考
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/