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 资源可能长这样:

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
  finalizers:  # 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文件内容

shell 复制代码
kubectl get ns monitoring   -o yaml 

可以发现果然是卡在Finalizer这里

要解决的话也很简单,把Finalizer的值设置为空即可。

把命名空间的配置文件导出为json格式

shell 复制代码
kubectl get ns monitoring  -o json > monitoring.json

编辑monitoring.json文件,把其中"kubernetes"包括引号全部删除

shell 复制代码
vim monitoring.json

变成实际上的空状态

接着同节点新开个终端,临时启动个api代理

shell 复制代码
kubectl proxy --port=8080

回到原终端执行api命令

shell 复制代码
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 状态的问题。以下是各部分的详细解释:

命令拆解

bash 复制代码
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 状态的问题。

重新再查看下发现已经被删除了

相关推荐
衍余未了4 小时前
k8s除了主server服务器可正常使用kubectl命令,其他节点不能使用原因,以及如何在其他k8s节点正常使用kubectl命令??
云原生·容器·kubernetes
Clownseven4 小时前
Mattermost教程:用Docker搭建自己的开源Slack替代品 (团队聊天)
docker·容器·开源
❀͜͡傀儡师4 小时前
Docker部署Drawnix开源白板工具
docker·容器·开源·drawnix
❀͜͡傀儡师4 小时前
Docker部署Lunalytics开源监控工具
docker·容器·开源·lunalytics
To_再飞行4 小时前
K8s 存储配置资源
linux·云原生·容器·kubernetes
To_再飞行6 小时前
K8s 调度管理
linux·云原生·kubernetes
milanyangbo7 小时前
“卧槽,系统又崩了!”——别慌,这也许是你看过最通俗易懂的分布式入门
分布式·后端·云原生·架构
大咖分享课7 小时前
系统越拆越乱?你可能误解了微服务的本质!
微服务·云原生·架构