当我们删除集群中的某个 namespace 之后,有时候 namespace 并没有按照我们的期望正常删除,而是一直卡在 Terminating 状态。本文主要讨论下 Terminating 状态发生的可能性以及解决办法。
删除 namespace 后发生了什么
我们从 kubectl delele namespace 动作开始,当执行了删除命名空间的动作后,k8s 并不会直接删除该命名空间,而是设置了 namespace 对象的 metadata.deleteTimestasp 字段,然后 kube-controlller-manager 组件中的 namespace-controller 开始工作,负责执行 namespace 删除的相关事宜,比如清理被删除命名空间下面的资源等,最后才会删除该命名空间,而如果 namespace-controller 有报错或者没有走到终止流程,就会一直卡在 Terminating 状态。
接下来先描述下 namespace-controller 的工作流程,如图所示:
image.png
可能原因 1:资源发现
k8s 的 api 组织形式
k8s 使用的是声明式 API,其中 API 是通过分组、版本、资源名组成,而谈论某个资源,必须要属于某个 API 分组 / 版本,比如通过 yaml 创建对象时,除了要声明 Kind 外,还需要声明 apiVersion 对象。
\# 查看资源
$ kubectl api\-resources \[\-o wide\]
# 查看API版本
$ kubectl api\-versions
聚合层扩展 kubernetes api
聚合层通常用于扩展 k8s api-server,允许添加新的 API 分组 / 版本。用户通过创建 apiService 对象来注册 API,并声明自定义的扩展 apiserver,当请求到该 API 分组 / 版本的时候,k8s apiservice 会代理转发到后端自定义的 apiserver 来处理。比如,TKE 集群中的 hpa-metrics-server,就实现了 metrics.k8s.io/v1beta1 这个 API 分组 / 版本(用户也可以部署 promethues 的 metrics-adapter 进行替换)。
在资源发现这里,会先获取 API 分组 / 版本信息,然后再获取各个 API 分组 / 版本的资源信息,从而罗列出集群中的所有资源。如果罗列资源发生报错,也有可能导致 namespace 卡主 Terminating 状态,常见于聚合层扩展 kubernetes api。
1、查看是 namespace 卡主 Terminating 的原因
$ kubectl get namespace <name\> \-o yaml
conditions:
\- lastTransitionTime: "2021-03-12T12:46:17Z"
message: 'Discovery failed for some groups, 1 failing: unable to retrieve the
complete list of server APIs: webhook.cert\-manager.io/v1beta1: the server is
currently unable to handle the request'
reason: DiscoveryFailed
status: "True"
type: NamespaceDeletionDiscoveryFailure
2、查看 apiservice 的状态
$ kubectl get apiservice
NAME SERVICE AVAILABLE AGE
v1beta1.webhook.cert\-manager.io cert\-manager/cert\-manager\-webhook False (ServiceNotFound) 3d23h
3、将异常的 apiservice 状态恢复成 True 或者删除不需要的 apiservice,即可恢复。
可能原因 2:finalizer
finalizer 导致 namespace Terminating 一般主要集群中以下两种情况:
1 namespace 资源对象的 spec.finalizer[] 列表中不为空
解决办法:手动清理
$ kubectl get ns delete\-me \-o json | jq '.spec.finalizers=\[\]' \> ns\-without\-finalizers.json
cat ns\-without\-finalizers.json
$ kubectl proxy &
$ PID\=$!
$ curl \-X PUT http://localhost:8001/api/v1/namespaces/delete\-me/finalize \-H "Content-Type: application/json" \--data\-binary @ns\-without\-finalizers.json
$ kill $PID
2 namespace 资源对象的 metadata.finalizer[] 列表不为空
比如:将集群托管到 rancher 管理后,rancher 就会写 finalizer 到 metadata.finalizer[] 列表,而当集群脱离 rancher 管理之后,手动删除 namespace,往往就会发生 Terminating
解决办法:
$ kubelet edit ns <name\> #将metadata.finalizer\[\]列表删除
原创声明,本文系作者授权云 + 社区发表,未经许可,不得转载。
如有侵权,请联系 yunjia_community@tencent.com 删除。
https://cloud.tencent.com/developer/article/1802531