K8s Resources Remove Procedure

說明 Kubernetes Finalizer 的作用、手動刪除資源造成殘留的情境,以及正確的資源與 namespace 移除流程。

發佈 ~1 分鐘 #K8s

前情提要:Finalizer 是什麼

  • 是 Kubernetes 設置在資源上的一種「刪除前必須操作」機制。
  • 有 Finalizer 的資源,Kubernetes 不會直接刪除,而是等待 Finalizer 執行完成,由 controller 清理相關資源,然後移除 Finalizer,最終刪除資源。

出錯情境

  • 刪 kube-prometheus-stack 時,Prometheus 的 CR (如 Prometheus / Alertmanager / ThanosRuler) 上還有 Finalizer,但是相關的 StatefulSet / Deployment 資源已被我手動先行刪除。
  • 後果:CR 的 Finalizer 未能正常完成,導致系統無法 finalize 資源,就會有残留的 Pod 存在,而其 owner (StatefulSet) 已絕緣,GC 無法自動刪 Pod。

原文情境

根據最之初提供的 Reddit 文:

  1. Kubernetes 刪 namespace 時,會執行全套資源檢查與削除流程,包括 Finalizer 處理。
  2. 如果遇到 stuck (Terminating 狀態不能解除),不應該直接 patch 刪掉 Finalizer,而應該看 describe ns 說明原因,並解決根本問題(例如刪掉已失效的 APIService)。
  3. 直接 patch Finalizer 會造成剩餘的 orphaned resources,需找出所有已絕緣的資源,並手動刪除。

正確移除流程

  1. 先不要動手 patch Finalizer!

  2. kubectl describe ns <namespace> 查看 stuck 原因,確認是哪個資源止住了流程?

  3. 處理根因(刪掉失效或異常資源):

    kubectl delete apiservices.apiregistration.k8s.io <example.com>
  4. 確認所有子資源正常被清除。

  5. 等 Kubernetes 自動 finalize namespace,如果已清理完,就會正常消失;否則才考慮手動消除。

若已發生錯誤 finalize,如何清理?

  • 使用下列 script 檢索 cluster 裡所有 orphaned resources,並手動把這些資源刪除:
#!/bin/bash
current_namespaces=($(kubectl get ns --no-headers | awk '{print $1}'))
api_resources=($(kubectl api-resources --verbs=list --namespaced -o name))
for api_resource in ${api_resources[@]}; do
    while IFS= read -r line; do
        resource_namespace=$(echo $line | awk '{print $1}')
        resource_name=$(echo $line | awk '{print $2}')
        if [[ ! " ${current_namespaces[@]} " =~ " $resource_namespace " ]]; then
            echo "api-resource: ${api_resource} - namespace: ${resource_namespace} - resource name: ${resource_name}"
        fi
    done < <(kubectl get $api_resource -A --ignore-not-found --no-headers -o custom-columns="NAMESPACE:.metadata.namespace,NAME:.metadata.name")
done

結論

Kubernetes 資源移除時,應按正規流程註意 Finalizer,先處理問題,再等待系統清理完成,避免使系統歷史紀錄與資源綁緣錯亂,別輕易直接打斷 Finalizer 流程!