本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
使用 Finalizers 控制刪除
刪除 Kubernetes 中的物件可能具有挑戰性。您可能認為您已刪除某些內容,但卻發現它仍然存在。雖然發出 kubectl delete
命令並祈禱最好的結果可能適用於日常操作,但了解 Kubernetes delete
命令的運作方式將有助於您了解為什麼某些物件在刪除後仍然存在。
在這篇文章中,我將探討
- 資源的哪些屬性控制刪除
- Finalizers 和擁有者參考如何影響物件刪除
- 如何使用傳播策略來變更刪除順序
- 刪除如何運作,並附帶範例
為了簡化起見,所有範例都將使用 ConfigMaps 和基本 Shell 命令來示範該過程。我們將探索命令如何運作,並討論在實務中使用它們的影響和結果。
基本的 delete
Kubernetes 有幾個不同的命令可以使用,讓您可以建立、讀取、更新和刪除物件。就本部落格文章而言,我們將重點關注四個 kubectl
命令:create
、get
、patch
和 delete
。
以下是基本 kubectl delete
命令的範例
kubectl create configmap mymap
configmap/mymap created
kubectl get configmap/mymap
NAME DATA AGE
mymap 0 12s
kubectl delete configmap/mymap
configmap "mymap" deleted
kubectl get configmap/mymap
Error from server (NotFound): configmaps "mymap" not found
以 $
開頭的 Shell 命令後面接著它們的輸出。您可以看到我們從 kubectl create configmap mymap
開始,這將建立空的 configmap mymap
。接下來,我們需要 get
configmap 以證明它存在。然後我們可以刪除該 configmap。嘗試再次 get
它會產生 HTTP 404 錯誤,這表示找不到 configmap。
基本 delete
命令的狀態圖非常簡單

刪除的狀態圖
雖然此操作很簡單,但其他因素可能會干擾刪除,包括 Finalizers 和擁有者參考。
了解 Finalizers
在了解 Kubernetes 中的資源刪除時,了解 Finalizers 的運作方式會很有幫助,並且可以協助您了解為什麼某些物件沒有被刪除。
Finalizers 是資源上表示刪除前操作的金鑰。它們控制資源上的垃圾收集,旨在提醒控制器在移除資源之前要執行的清理操作。但是,它們不一定命名應執行的程式碼;資源上的 Finalizers 基本上只是金鑰清單,很像註釋。與註釋類似,它們可以被操作。
您可能遇到的一些常見 Finalizers 是
kubernetes.io/pv-protection
kubernetes.io/pvc-protection
上面的 Finalizers 用於磁碟區以防止意外刪除。同樣地,某些 Finalizers 可用於防止刪除任何資源,但不受任何控制器管理。
以下是一個自訂 configmap,它沒有任何屬性,但包含 Finalizer
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: mymap
finalizers:
- kubernetes
EOF
configmap 資源控制器不了解如何處理 kubernetes
Finalizer 金鑰。我將這些 configmap 的 Finalizers 稱為「無效」Finalizers,因為它通常用於命名空間。以下是嘗試刪除 configmap 時發生的情況
kubectl delete configmap/mymap &
configmap "mymap" deleted
jobs
[1]+ Running kubectl delete configmap/mymap
Kubernetes 將回報物件已刪除,但是,它並未以傳統意義上的方式刪除。相反地,它正在刪除過程中。當我們嘗試再次 get
該物件時,我們發現該物件已被修改為包含刪除時間戳記。
kubectl get configmap/mymap -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: "2020-10-22T21:30:18Z"
deletionGracePeriodSeconds: 0
deletionTimestamp: "2020-10-22T21:30:34Z"
finalizers:
- kubernetes
name: mymap
namespace: default
resourceVersion: "311456"
selfLink: /api/v1/namespaces/default/configmaps/mymap
uid: 93a37fed-23e3-45e8-b6ee-b2521db81638
簡而言之,發生的情況是物件已更新,而不是刪除。那是因為 Kubernetes 看到物件包含 Finalizers 並阻止從 etcd 中移除物件。刪除時間戳記表示已請求刪除,但在我們編輯物件並移除 Finalizer 之前,刪除將不會完成。
以下是如何使用 patch
命令移除 Finalizers 的示範。如果我們要刪除物件,我們可以簡單地在命令列上修補它以移除 Finalizers。透過這種方式,在背景中執行的刪除將會完成,並且物件將被刪除。當我們嘗試 get
該 configmap 時,它將會消失。
kubectl patch configmap/mymap \
--type json \
--patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]'
configmap/mymap patched
[1]+ Done kubectl delete configmap/mymap
kubectl get configmap/mymap -o yaml
Error from server (NotFound): configmaps "mymap" not found
以下是 Finalization 的狀態圖

Finalize 的狀態圖
因此,如果您嘗試刪除具有 Finalizer 的物件,它將保持 Finalization 狀態,直到控制器移除 Finalizer 金鑰或使用 Kubectl 移除 Finalizers。一旦 Finalizer 清單為空,物件實際上就可以被 Kubernetes 回收並放入佇列中,以便從登錄檔中刪除。
擁有者參考
擁有者參考描述了物件群組之間的關係。它們是資源上的屬性,用於指定彼此之間的關係,因此可以刪除整個資源樹狀結構。
當存在擁有者參考時,將處理 Finalizer 規則。擁有者參考包含名稱和 UID。擁有者參考連結相同命名空間內的資源,並且它也需要 UID 才能使該參考生效。Pod 通常具有指向擁有複本集的所有者參考。因此,當刪除部署或 Stateful Set 時,子複本集和 Pod 也會在過程中被刪除。
以下是一些擁有者參考及其運作方式的範例。在第一個範例中,我們先建立父物件,然後建立子物件。結果是一個非常簡單的 configmap,其中包含對其父物件的擁有者參考
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: mymap-parent
EOF
CM_UID=$(kubectl get configmap mymap-parent -o jsonpath="{.metadata.uid}")
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: mymap-child
ownerReferences:
- apiVersion: v1
kind: ConfigMap
name: mymap-parent
uid: $CM_UID
EOF
當涉及擁有者參考時,刪除子物件不會刪除父物件
kubectl get configmap
NAME DATA AGE
mymap-child 0 12m4s
mymap-parent 0 12m4s
kubectl delete configmap/mymap-child
configmap "mymap-child" deleted
kubectl get configmap
NAME DATA AGE
mymap-parent 0 12m10s
在此範例中,我們從上面重新建立了父子 configmap。現在,當從父物件(而不是子物件)刪除時,子物件具有到父物件的擁有者參考,當我們 get
configmap 時,命名空間中沒有任何 configmap
kubectl get configmap
NAME DATA AGE
mymap-child 0 10m2s
mymap-parent 0 10m2s
kubectl delete configmap/mymap-parent
configmap "mymap-parent" deleted
kubectl get configmap
No resources found in default namespace.
總而言之,當從子物件到父物件存在覆寫擁有者參考時,刪除父物件會自動刪除子物件。這稱為 cascade
。cascade 的預設值為 true
,但是,您可以將 --cascade=orphan 選項用於 kubectl delete
,以刪除物件並孤立其子物件。更新:從 kubectl v1.20 開始,cascade 的預設值為 background
。
在以下範例中,有一個父物件和一個子物件。請注意,仍然包含擁有者參考。如果我使用 --cascade=orphan 刪除父物件,則父物件將被刪除,但子物件仍然存在
kubectl get configmap
NAME DATA AGE
mymap-child 0 13m8s
mymap-parent 0 13m8s
kubectl delete --cascade=orphan configmap/mymap-parent
configmap "mymap-parent" deleted
kubectl get configmap
NAME DATA AGE
mymap-child 0 13m21s
--cascade 選項連結到 API 中的傳播策略,您可以使用該策略變更樹狀結構中物件的刪除順序。以下範例使用 API 存取來製作具有背景傳播策略的自訂刪除 API 呼叫
kubectl proxy --port=8080 &
Starting to serve on 127.0.0.1:8080
curl -X DELETE \
localhost:8080/api/v1/namespaces/default/configmaps/mymap-parent \
-d '{ "kind":"DeleteOptions", "apiVersion":"v1", "propagationPolicy":"Background" }' \
-H "Content-Type: application/json"
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Success",
"details": { ... }
}
請注意,無法使用 kubectl 在命令列上指定傳播策略。您必須使用自訂 API 呼叫來指定它。只需建立一個 Proxy,以便您可以從用戶端存取 API 伺服器,然後執行一個 curl
命令,其中僅包含一個 URL 來執行該 delete
命令。
傳播策略有三個不同的選項
Foreground
:子物件在父物件之前刪除(後序)Background
:父物件在子物件之前刪除(前序)Orphan
:忽略擁有者參考
請記住,當您刪除物件並已指定擁有者參考時,在此過程中將會遵循 Finalizers。這可能會導致物件樹狀結構持續存在,並且您最終會得到部分刪除。在這種情況下,您必須查看物件上的任何現有擁有者參考以及任何 Finalizers,以了解正在發生的情況。
強制刪除命名空間
有一種情況可能需要強制 Finalization 命名空間。如果您已刪除命名空間並清除了其下的所有物件,但命名空間仍然存在,則可以透過更新命名空間子資源 finalize
來強制刪除。這會通知命名空間控制器,它需要從命名空間中移除 Finalizer 並執行任何清理
cat <<EOF | curl -X PUT \
localhost:8080/api/v1/namespaces/test/finalize \
-H "Content-Type: application/json" \
--data-binary @-
{
"kind": "Namespace",
"apiVersion": "v1",
"metadata": {
"name": "test"
},
"spec": {
"finalizers": null
}
}
EOF
應謹慎執行此操作,因為它可能僅刪除命名空間,並將孤立物件留在現在不存在的命名空間中 - 這對 Kubernetes 來說是一種令人困惑的狀態。如果發生這種情況,可以手動重新建立命名空間,有時孤立物件將重新出現在剛建立的命名空間下,這將允許手動清理和復原。
重點摘要
正如這些範例所示,Finalizers 可能會妨礙刪除 Kubernetes 中的資源,尤其是在物件之間存在父子關係時。通常,在程式碼中新增 Finalizer 是有原因的,因此您應該始終在手動刪除它之前進行調查。擁有者參考允許您指定和移除資源樹狀結構,儘管在此過程中將會遵循 Finalizers。最後,傳播策略可用於透過自訂 API 呼叫指定刪除順序,讓您控制物件的刪除方式。現在您對 Kubernetes 中刪除的運作方式有更多了解,我們建議您在自己的測試叢集上試用它。