当我们删除集群中的某个namespace之后,有时候namespace并没有按照我们的期望正常删除,而是一直卡在Terminating状态。本文主要讨论下Terminating状态发生的可能性以及解决办法。
删除namespace后发生了什么
我们从kubectl delele namespace动作开始,当执行了删除命名空间的动作后,k8s并不会直接删除该命名空间,而是设置了namespace对象的metadata.deleteTimestasp字段,然后kube-controlller-manager组件中的namespace-controller开始工作,负责执行namespace删除的相关事宜,比如清理被删除命名空间下面的资源等,最后才会删除该命名空间,而如果namespace-controller有报错或者没有走到终止流程,就会一直卡在Terminating状态。
接下来先描述下namespace-controller的工作流程,如图所示:
可能原因1:资源发现
k8s的api组织形式
k8s使用的是声明式API,其中API是通过分组、版本、资源名组成,而谈论某个资源,必须要属于某个API分组/版本,比如通过yaml创建对象时,除了要声明Kind外,还需要声明apiVersion对象。
代码语言:txt复制# 查看资源
$ 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的原因
代码语言:txt复制$ 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的状态
代码语言:txt复制$ 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[] 列表中不为空
解决办法:手动清理
代码语言:txt复制$ 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
解决办法:
代码语言:txt复制$ kubelet edit ns <name> #将metadata.finalizer[]列表删除