K8S删除命名空间卡住一直Terminating状态
背景
在命名空间下有资源,直接删除命名空间的时候一直Terminating状态,看样子是一直在处理删除操作,但卡在这里没有继续进度,导致实际完全没有执行删除操作。
在解决这个问题前需要先了解下k8s删除相关的概念
以我的总结就是卡在Terminating状态,资源Finalizer处理堵塞未完成导致关联存在无法删除成功,一直处于在处理中但实际并没有处理任务。
Finalizer是什么?
在 Kubernetes(K8s)中,Finalizer 是一种用于控制资源删除流程的 “钩子机制”,它的核心作用是:确保资源在被彻底删除前,必须完成预设的前置操作(如数据清理、外部系统同步、依赖关系解除等)。
简单来说就是在删除前,解决这个资源所有与之相关的调用使用占用解绑,比如说pod绑定了pvc,要删除这个pod,就会通过Finalizer解除pod与pvc的关联,然后K8S再执行删除操作。
Finalizer 是存储在资源对象 metadata.finalizers 字段中的一组字符串列表(格式通常为 /,如 kubernetes.io/pvc-protection)。
例如,一个带有 Finalizer 的 PVC 资源可能长这样:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: my-pvcfinalizers: # Finalizer 列表- kubernetes.io/pvc-protection # 内置 Finalizer,保护 PVC 不被意外删除
spec:
...
Finalizer 的工作原理
当你对一个带有 Finalizer 的资源执行 kubectl delete 时,Kubernetes 的删除流程会发生变化:
标记 “待删除”
:K8s 首先会给资源添加 deletionTimestamp 字段(记录删除请求的时间),但不会立即删除资源,资源状态会变为 Terminating。
等待 Finalizer 处理
:K8s 会检查 metadata.finalizers 列表,若列表不为空,会等待对应的 “控制器”(Controller)处理这些 Finalizer。
移除 Finalizer
:控制器完成预设操作(如 PVC 解绑、数据备份)后,会从列表中移除对应的 Finalizer。
彻底删除资源
:当 metadata.finalizers 列表为空时,K8s 才会真正删除该资源(从 etcd 中移除记录)。
Terminating状态问题出现原因
在命名空间包含资源的情况下删除整个命名空间时,可能会出现 Finalizer 阻止删除的情况,但这与 “命名空间内有残留资源” 并非 “冲突关系”,而是因果关联或并存关系——Finalizer 往往是导致 “资源无法删除(形成残留)” 的核心原因,进而间接导致命名空间删除停滞。
它分为两种场景,都会影响命名空间删除:
场景 1:命名空间内的资源自身带有 Finalizer,导致资源无法删除(形成 “残留资源”)
这是最常见的情况。如果命名空间内的某个资源(如 PVC、Pod、StatefulSet)带有未处理的 Finalizer,会导致该资源无法被删除,进而使得命名空间的 “级联删除” 流程卡在第一步(资源清理阶段),表现为 “命名空间内有残留资源”,但根源是 资源的 Finalizer 未被处理。
举例:
PVC 的 kubernetes.io/pvc-protection Finalizer:若 PVC 绑定的 PV 未被正确释放(如 PV 是 Retain 回收策略),该 Finalizer 会阻止 PVC 被删除,导致 PVC 成为 “残留资源”,命名空间删除停滞。
Pod 的 pod.kubernetes.io/foregroundDeletion Finalizer:若 Pod 关联的控制器(如 StatefulSet)故障,无法完成 Pod 的前置清理(如数据卸载),该 Finalizer 会阻止 Pod 删除,形成残留。
自定义资源(CR)的 Finalizer:若命名空间内有自定义资源(如 Rook-Ceph 的 CephCluster),其对应的控制器(Operator)未正常运行,无法处理 CR 的 Finalizer(如数据卷解绑),会导致 CR 无法删除,成为残留资源。
此时,“残留资源” 是结果,“资源自身的 Finalizer 未处理” 是原因。
场景 2:命名空间自身带有 Finalizer,导致命名空间无法被最终删除
命名空间对象(Namespace)自身也有 spec.finalizers 字段(默认包含 kubernetes 这个 Finalizer),其作用是:确保 K8s 控制器已完成对该命名空间内所有资源的级联删除后,才允许删除命名空间本身。
若命名空间内的资源因各种原因(包括资源自身的 Finalizer 未处理)无法删除(形成残留),Kubernetes 会认为 “资源清理未完成”,从而不会移除命名空间自身的 kubernetes Finalizer,导致命名空间卡在 Terminating 状态。
此时,“命名空间自身的 Finalizer 未被移除” 是结果,“命名空间内有残留资源(可能由资源 Finalizer 导致)” 是原因。
三、“Finalizer 阻止删除” 与 “命名空间内有残留资源” 的关系:不冲突,常伴随
两者并非 “冲突关系”(冲突意味着互斥,只能存在一个),而是 “因果关系” 或 “并存关系”:
Finalizer和资源残留导致的无法删除区别
因果关系 资源自身的 Finalizer 未处理 → 资源无法删除(形成残留)→ 命名空间级联删除卡住 → 命名空间自身的 Finalizer 无法移除 → 命名空间删除被阻止。
并存关系 即使资源自身没有 Finalizer,但因控制器故障(如 API Server 异常)导致资源无法删除(残留),同时命名空间自身的 Finalizer 因 “资源未清理” 而无法移除,两者同时存在。
总结:两者本质是 “问题的不同层面”——“残留资源” 是现象,“Finalizer 未处理” 是常见根源(可能是资源的 Finalizer,也可能是命名空间自身的 Finalizer)。
Terminating状态问题处理方法
以我的环境为例,在有资源的情况下直接删除monitoring结果卡住无法删除
先看下运行中的yaml文件内容
kubectl get ns monitoring -o yaml
可以发现果然是卡在Finalizer这里
要解决的话也很简单,把Finalizer的值设置为空即可。
把命名空间的配置文件导出为json格式
kubectl get ns monitoring -o json > monitoring.json
编辑monitoring.json文件,把其中"kubernetes"包括引号全部删除
vim monitoring.json
变成实际上的空状态
接着同节点新开个终端,临时启动个api代理
kubectl proxy --port=8080
回到原终端执行api命令
curl -X PUT http://localhost:8080/api/v1/namespaces/monitoring/finalize -H "Content-Type: application/json" -d @monitoring.json
curl -X PUT http://localhost:8080/api/v1/namespaces/命名空间/finalize -H "Content-Type: application/json" -d @导出的文件名.json
这个 curl 命令的作用是 通过 Kubernetes API 强制完成 monitoring 命名空间的删除流程,主要用于解决该命名空间卡在 Terminating 状态的问题。以下是各部分的详细解释:
命令拆解
curl -X PUT \http://localhost:8080/api/v1/namespaces/monitoring/finalize \-H "Content-Type: application/json" \-d @monitoring.json
curl
是一个命令行工具,用于发送 HTTP/HTTPS 请求,这里用于与 Kubernetes API 服务器交互。
-X PUT
指定 HTTP 请求方法为 PUT,用于更新已存在的资源。在 Kubernetes 中,PUT 通常用于修改资源的配置(这里是修改命名空间的删除相关配置)。
http://localhost:8080/api/v1/namespaces/monitoring/finalize
这是请求的目标 URL,指向 Kubernetes API 的特定端点,含义如下:
-
localhost:8080:通过 kubectl proxy 启动的本地代理端口(用于将请求转发到Kubernetes 集群的 API 服务器,避免直接处理认证复杂问题)。
-
/api/v1:Kubernetes 核心 API 的版本路径(固定格式)。
-
/namespaces/monitoring:指定操作的资源是名为 monitoring 的命名空间。
-
/finalize:命名空间删除的 “终结端点”,专门用于处理命名空间删除时的最终清理(尤其是解决 Finalizers 阻塞问题)。
-H “Content-Type: application/json”
设置 HTTP 请求头,声明请求体的数据格式为 JSON(Kubernetes API 仅接受 JSON 格式的请求数据)。
-d @monitoring.json
指定请求体的内容来源:
-d 表示 “请求体数据”。
@monitoring.json 表示读取当前目录下 monitoring.json 文件的内容作为请求体(@ 符号是 curl 中 “读取文件内容” 的语法)。
该 monitoring.json 文件需要包含 monitoring 命名空间的关键配置,通常需满足:
保留原命名空间的 metadata.uid(确保操作的是同一个命名空间)。
将 spec.finalizers 设为 [](空数组),以移除阻塞删除的终结器(Finalizers)。
最终目的
通过这个命令,向 Kubernetes API 发送修改后的 monitoring 命名空间配置(清除阻塞删除的 Finalizers),强制触发命名空间的删除流程,解决其卡在 Terminating 状态的问题。
重新再查看下发现已经被删除了