排障记录:删除Namespace olm一直Terminating的处理过程
引言
在集群日常维护中,删除一个 Namespace 看起来是“删掉一堆资源”的简单动作,但如果控制面无法完成资源发现(discovery),或某些资源的 finalizers 无法被对应控制器清理,Namespace 就会长期卡在 Terminating。
本文记录一次删除 olm Namespace 失败的排障过程:先是 NamespaceDeletionDiscoveryFailure,解决后又卡在 ClusterServiceVersion(CSV)清理阶段,最终通过移除 CSV 的 finalizer 完成删除。文末附一套可复用的排查清单与风险提示。
警告:
olm相关资源通常属于 Operator Lifecycle Manager(OLM)核心组件。生产集群中不建议随意删除;本文的“强制移除 finalizer / 删除 APIService”属于应急手段,务必理解影响范围后再执行。
现象:Namespace olm 一直 Terminating
删除 olm 后一直停留在 Terminating,查看 Namespace 状态发现:
1 | Discovery failed for some groups, 1 failing: unable to retrieve the |
这条信息的关键点是:控制面在做“列出该 Namespace 下所有资源类型并逐一清理”之前,需要先完成 API discovery;而 discovery 过程中,packages.operators.coreos.com/v1 这个聚合 API(aggregated API)无法正常返回,导致删除流程被阻塞。
第一步:从 Namespace Conditions 定位阻塞点
建议第一时间看 Namespace 的 conditions(比“盲删 finalizers”更快定位根因):
1 | kubectl describe namespace olm |
其中 NamespaceDeletionDiscoveryFailure=True 通常意味着:有 API group/version 在 discovery 阶段不可用,Namespace lifecycle controller 无法确认“有哪些资源类型需要被列出并清理”。
根因一:v1.packages.operators.coreos.com APIService 不可用(ServiceNotFound)
根据报错指向的 group/version,去查对应的 APIService:
1 | kubectl get apiservice v1.packages.operators.coreos.com |
输出类似:
1 | NAME SERVICE AVAILABLE AGE |
这里的信号非常明确:该聚合 API 通过 APIService 挂到 kube-apiserver 的 aggregation layer 上,后端需要一个真实存在且健康的 Service(这里是 olm/packageserver-service)。当它变成 False (ServiceNotFound) 时,kube-apiserver 仍会把这个 API 组暴露在 discovery 路径里,但向后端代理请求会失败,从而触发 Namespace 删除流程的 discovery failure。
你可以进一步核实 Service 是否存在:
1 | kubectl -n olm get svc packageserver-service |
处理一:优先恢复 packageserver(推荐),否则删除 APIService(应急)
方案A:恢复后端服务(推荐)
如果这是生产集群或你仍需要 OLM 能力,优先做“把 packageserver-service 对应的 Deployment/Pod 修复回来”,让 APIService 变为可用(AVAILABLE=True)。这样 deletion discovery 能自然恢复,后续清理也更可控。
方案B:删除不可用的 APIService(应急)
如果你明确不再需要该聚合 API(例如正在拆除 OLM / 清理残留),可以删除这个 APIService,让 kube-apiserver 的 discovery 不再包含该 group/version,从而解除 Namespace 删除的 discovery 阻塞:
1 | kubectl delete apiservice v1.packages.operators.coreos.com |
注意:删除后会影响依赖该 API 的能力(例如 OLM 的
packagemanifest查询等),请在维护窗口评估影响后再做。
执行后你会观察到:很多此前卡在 Terminating 的 Namespace 会被快速清理。但这次事故里,olm 仍然没有被删掉,说明还有第二个阻塞点。
第二步:Discovery 恢复后,继续看“剩余资源 + 剩余 finalizers”
此时再次 describe Namespace,会看到 discovery 相关条件已恢复,但出现另外两条:
1 | NamespaceContentRemaining True SomeResourcesRemain ... clusterserviceversions.operators.coreos.com has 1 resource instances |
这两条意味着:
- Namespace 里仍有资源实例没删干净(这里是
ClusterServiceVersion) - 且该资源实例上仍挂着 finalizer(这里是
operators.coreos.com/csv-cleanup),控制器没有完成清理并移除 finalizer
根因二:CSV packageserver 残留,csv-cleanup finalizer 无法被清理
列出 olm 下的 CSV:
1 | kubectl get csv -n olm |
输出示例:
1 | NAMESPACE NAME DISPLAY VERSION REPLACES PHASE |
此时典型情况是:OLM 相关控制器(负责执行 operators.coreos.com/csv-cleanup)已经不可用或不再工作,导致 finalizer 永远不会被自动移除,进而阻塞 CSV 删除,也阻塞 Namespace 最终删除。
处理二:手动清理 CSV(最后手段:移除 finalizers)
优先尝试正常删除
如果控制器仍然健康,直接删除 CSV 即可:
1 | kubectl delete csv packageserver -n olm |
控制器失效时:移除 CSV finalizers
当 CSV 一直删不掉(或你已确认需要强制清理),可通过 patch 移除 finalizers:
1 | kubectl patch csv packageserver -n olm \ |
执行后,CSV 会被立即释放,随后 olm Namespace 也会自动完成终止并消失。
为什么“删 namespace 的 spec.finalizers”不一定有用?
很多人第一反应是把 Namespace 的 spec.finalizers 清空,但这在本案里无效,原因有两类:
- Discovery 阶段就失败:控制器连“这个 Namespace 里有哪些资源类型要清理”都无法完整发现,删除流程会直接卡住。
- 资源级 finalizer 才是硬阻塞:即使 Namespace 自身 finalizer 被清空,只要 Namespace 内仍有带 finalizer 的资源(例如 CSV),最终删除仍会被阻塞。
换句话说:Namespace 是“结果”,资源与控制器的健康才是“原因”。
一套可复用的排查清单(推荐按顺序执行)
1. 看清楚卡在哪一类 condition
1 | kubectl describe namespace <ns> |
NamespaceDeletionDiscoveryFailure=True:优先查APIService/聚合 API/网络/后端服务NamespaceContentRemaining=True:说明仍有资源残留NamespaceFinalizersRemaining=True:说明仍有资源 finalizer 没被清理
2. 找出所有不可用的 APIService
1 | kubectl get apiservice | grep False |
3. 枚举 Namespace 内仍然存在的资源(通用方法)
1 | kubectl api-resources --verbs=list --namespaced -o name | \ |
4. 针对“有 finalizer 的残留资源”做精准清理
以本案为例:
1 | kubectl get csv -n <ns> |
确认 finalizers 后,再决定是否移除(强制手段)。
5. 最后手段:强制完成 Namespace finalize(谨慎)
如果你已经:
- 修复/移除了不可用的
APIService(不再触发 discovery failure) - 手工清理了 Namespace 内的残留资源(或你已接受残留风险)
仍然无法删除 Namespace,可以考虑通过 finalize 端点强制移除 spec.finalizers(参考 GKE 文档的流程)。这是高风险操作,可能导致集群中遗留“看不见但还存在”的资源。
1 | kubectl get ns <ns> -o yaml > ns-terminating.yml |
风险提示与建议
- 能修复控制器就别强拆 finalizer:finalizer 本意是保证清理动作被执行;直接移除意味着你承诺“后果自负”,后续可能留下孤儿资源或脏数据。
- 删除 APIService 是在“切断聚合 API 的入口”:它能让 discovery 变干净,但也会让对应 API 彻底不可用。更推荐先恢复后端服务。
- 系统组件 Namespace 要谨慎:如果是 OpenShift 集群内置的 OLM(例如
openshift-operator-lifecycle-manager等),不要照搬本文对系统命名空间的删除操作。
参考链接
- Kubernetes Finalizers:
https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/ - Kubernetes API Aggregation Layer:
https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/ - Configure the Aggregation Layer:
https://kubernetes.io/docs/tasks/extend-kubernetes/configure-aggregation-layer/ - GKE:Troubleshoot namespace stuck in the Terminating state:
https://cloud.google.com/kubernetes-engine/docs/troubleshooting/terminating-namespaces - OLM:ClusterServiceVersion(概念)
https://olm.operatorframework.io/docs/concepts/crds/clusterserviceversion/ - OLM:PackageManifest API(列出可安装 Operator)
https://olm.operatorframework.io/docs/tasks/list-operators-available-to-install/
本文由 AI 辅助生成,如有错误或建议,欢迎指出。


