当我们删除集群中的某个 namespace 之后,有时候 namespace 并没有按照我们的期望正常删除,而是一直卡在 Terminating 状态。本文主要讨论下 Terminating 状态发生的可能性以及解决办法。

删除 namespace 后发生了什么

我们从 kubectl delele namespace 动作开始,当执行了删除命名空间的动作后,k8s 并不会直接删除该命名空间,而是设置了 namespace 对象的 metadata.deleteTimestasp 字段,然后 kube-controlller-manager 组件中的 namespace-controller 开始工作,负责执行 namespace 删除的相关事宜,比如清理被删除命名空间下面的资源等,最后才会删除该命名空间,而如果 namespace-controller 有报错或者没有走到终止流程,就会一直卡在 Terminating 状态。

接下来先描述下 namespace-controller 的工作流程,如图所示:

删除namespace为什么会Terminating? - 云 社区 - 腾讯云 - 图1

image.png

可能原因 1:资源发现

k8s 的 api 组织形式

k8s 使用的是声明式 API,其中 API 是通过分组、版本、资源名组成,而谈论某个资源,必须要属于某个 API 分组 / 版本,比如通过 yaml 创建对象时,除了要声明 Kind 外,还需要声明 apiVersion 对象。

  1. \# 查看资源
  2. $ kubectl api\-resources \[\-o wide\]
  3. # 查看API版本
  4. $ 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

相关链接:https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/namespaces.md#rest-api

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