![null](http://static.javashuo.com/static/loading.gif)
前言
常常操做 Kubernetes 集羣的同窗確定對 finalizers
字段不陌生,每當刪除 namespace 或 pod 等一些 Kubernetes 資源時,有時資源狀態會卡在 Terminating
,很長時間沒法刪除,甚至有時增長 --force
flag 以後仍是沒法正常刪除。這時就須要 edit
該資源,將 finalizers
字段設置爲 [],以後 Kubernetes 資源就正常刪除了。react
這是一個比較常見的操做,可是當有人問 finalizers
字段的做用是什麼的時候,我是懵逼的,我甚至不知道這個熟悉又陌生的單詞怎麼讀!那麼這篇文章就來探索一下 finalizers
這個字段究竟是作什麼的,在實踐中應該怎麼應用這個字段。(另外,這個單詞讀做 ['faɪnəlaɪzər])git
Finalizers
Finalizers 字段屬於 Kubernetes GC 垃圾收集器,是一種刪除攔截機制,可以讓控制器實現異步的刪除前(Pre-delete)回調。其存在於任何一個資源對象的 Meta[1] 中,在 k8s 源碼中聲明爲 []string
,該 Slice 的內容爲須要執行的攔截器名稱。github
對帶有 Finalizer 的對象的第一個刪除請求會爲其 metadata.deletionTimestamp
設置一個值,但不會真的刪除對象。一旦此值被設置,finalizers 列表中的值就只能被移除。web
當 metadata.deletionTimestamp
字段被設置時,負責監測該對象的各個控制器會經過輪詢對該對象的更新請求來執行它們所要處理的全部 Finalizer。當全部 Finalizer 都被執行過,資源被刪除。json
metadata.deletionGracePeriodSeconds
的取值控制對更新的輪詢週期。api
每一個控制器要負責將其 Finalizer 從列表中去除。微信
每執行完一個就從 finalizers
中移除一個,直到 finalizers
爲空,以後其宿主資源纔會被真正的刪除。架構
// DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This// field is set by the server when a graceful deletion is requested by the user, and is not// directly settable by a client. The resource is expected to be deleted (no longer visible// from resource lists, and not reachable by name) after the time in this field, once the// finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.// Once the deletionTimestamp is set, this value may not be unset or be set further into the// future, although it may be shortened or the resource may be deleted prior to this time.// For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react// by sending a graceful termination signal to the containers in the pod. After that 30 seconds,// the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,// remove the pod from the API. In the presence of network partitions, this object may still// exist after this timestamp, until an administrator or automated process can determine the// resource is fully terminated.// If not set, graceful deletion of the object has not been requested.//// Populated by the system when a graceful deletion is requested.// Read-only.// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata// +optionalDeletionTimestamp *Time `json:"deletionTimestamp,omitempty" protobuf:"bytes,9,opt,name=deletionTimestamp"`// Number of seconds allowed for this object to gracefully terminate before// it will be removed from the system. Only set when deletionTimestamp is also set.// May only be shortened.// Read-only.// +optionalDeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty" protobuf:"varint,10,opt,name=deletionGracePeriodSeconds"`// Must be empty before the object is deleted from the registry. Each entry// is an identifier for the responsible component that will remove the entry// from the list. If the deletionTimestamp of the object is non-nil, entries// in this list can only be removed.// Finalizers may be processed and removed in any order. Order is NOT enforced// because it introduces significant risk of stuck finalizers.// finalizers is a shared field, any actor with permission can reorder it.// If the finalizer list is processed in order, then this can lead to a situation// in which the component responsible for the first finalizer in the list is// waiting for a signal (field value, external system, or other) produced by a// component responsible for a finalizer later in the list, resulting in a deadlock.// Without enforced ordering finalizers are free to order amongst themselves and// are not vulnerable to ordering changes in the list.// +optional// +patchStrategy=mergeFinalizers []string `json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"`
在 Operator 中的應用
知道了 Finalizers 是什麼,那麼固然也要知道怎麼用 Finalizers 了。在實際開發 Operator 時,刪除前(Pre-delete)回調是一個比較常見的功能,用於處理一些在資源刪除前須要處理的邏輯,如:關聯資源釋放、釋放資源通知、相關數據清理,甚至是阻止資源刪除。通常 Finalizers 的處理也是會 Reconcile
中實現的,下面就使用 chaosblade-operator[2] 中的源碼,簡單介紹一些 Finalizers 的使用方式。app
首先要了解的是 ChaosBlade-Operator 的工做原理:每一個實驗都會以 CR 的形式部署到 k8s 集羣中,以後由 chaosblade-operator
來操做以 DaemonSet 形式部署 chaosblade-tool
對具體資源進行混沌實驗。中止實驗只需刪除對應 CR 便可,在刪除 CR 時,首先會執行一遍實驗恢復邏輯,以後纔會將 CR 刪除。但若是恢復實驗失敗,則會將 CR 的 Phase
設置爲 Destroying
,而在 Reconcile
中觀測到 Phase
狀態爲 Destroying
或者 metadata.deletionTimestamp
不爲空時,就會不會移除 finalizers
中的攔截器名稱,阻止該 CR 被刪除。異步
這樣設計的目的是爲了在實驗恢復失敗後,讓用戶去主動查看實驗恢復失敗緣由,若是是一些意外緣由致使的實驗恢復失敗,及時去處理。在確認緣由後,可以使用 CLI 工具增長 --force-remove
進去強制刪除,項目維護者在 Issue#368[3] 中也就這個設計給出瞭解答。
// pkg/controller/chaosblade/controller.go 部分源碼...const chaosbladeFinalizer = "finalizer.chaosblade.io"...func (r *ReconcileChaosBlade) Reconcile(request reconcile.Request) (reconcile.Result, error) { reqLogger := logrus.WithField("Request.Name", request.Name) forget := reconcile.Result{} // Fetch the RC instance cb := &v1alpha1.ChaosBlade{} err := r.client.Get(context.TODO(), request.NamespacedName, cb) if err != nil { return forget, nil } if len(cb.Spec.Experiments) == 0 { return forget, nil } // Destroyed->delete // Remove the Finalizer if the CR object status is destroyed to delete it if cb.Status.Phase == v1alpha1.ClusterPhaseDestroyed { cb.SetFinalizers(remove(cb.GetFinalizers(), chaosbladeFinalizer)) err := r.client.Update(context.TODO(), cb) if err != nil { reqLogger.WithError(err).Errorln("remove chaosblade finalizer failed at destroyed phase") } return forget, nil } if cb.Status.Phase == v1alpha1.ClusterPhaseDestroying || cb.GetDeletionTimestamp() != nil { err := r.finalizeChaosBlade(reqLogger, cb) if err != nil { reqLogger.WithError(err).Errorln("finalize chaosblade failed at destroying phase") } return forget, nil } ... return forget, nil}
若是 Phase
狀態爲 Destroyed
,則從 Finalizers 中移除 finalizer.chaosblade.io
,以後正常刪除 CR。
結語
在實際工做中,像 Finalizers 這樣的東西太多了,不少平時掛在嘴邊的東西,深究起來咱們可能對其並不瞭解,甚至本來的理解就是錯誤的。在從此的文章中,除了各類實踐乾貨,筆者還會將更多的精力投注到基本原理、底層實現、源碼剖析中,更聚焦於技術自己,在不重複造輪子的基礎上,學習和了解更多產品背後的代碼設計和實現原理。最後在分享一句弗蘭西斯·培根的話:
「人生如同道路。最近的捷徑一般是最壞的路。」
![](http://static.javashuo.com/static/loading.gif)
引用連接
[1]
Meta: https://github.com/kubernetes/apimachinery/blob/master/pkg/apis/meta/v1/types.go#L246[2]
chaosblade-operator: https://github.com/chaosblade-io/chaosblade-operator[3]
Issue#368: https://github.com/chaosblade-io/chaosblade/issues/368
本文分享自微信公衆號 - 僞架構師(fake-architect)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。