k8s 命名空间Terminating产生原因及解决方法

为什么删除ns会出现Terminating的情况

当删除集群中的某个namespace之后,有时候namespace并没有按照我们的期望正常删除,而是一直卡在Terminating状态。

删除namespace后到底发生了什么

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

namespace-controller的工作流程,如图所示:

es_user

状态

使用kubectl delete -f xxx.yaml,再次执行 kubectl apply -f xxx.yaml,提示:

1
2
3
4
5
6
7
8
9
10
11
12
13
➜  fb git:(master) kubectl apply -f .
Error from server (Forbidden): error when creating "kubesphere-complete-setup.yaml": configmaps "ks-installer" is forbidden: unable to create new content in namespace kubesphere-system because it is being terminated
Error from server (Forbidden): error when creating "kubesphere-complete-setup.yaml": serviceaccounts "ks-installer" is forbidden: unable to create new content in namespace kubesphere-system because it is being terminated
Error from server (Forbidden): error when creating "kubesphere-complete-setup.yaml": deployments.apps "ks-installer" is forbidden: unable to create new content in namespace kubesphere-system because it is being terminated

➜ fb git:(master) kubectl get ns
NAME STATUS AGE
default Active 15h
kube-node-lease Active 15h
kube-public Active 15h
kube-system Active 15h
cattle-system Terminating 28m
Local Terminating 28m

原因及解决方法

原因1:finalizer(main)

finalizer导致namespace Terminating一般主要集群中以下两种情况:

1. namespace资源对象的spec.finalizer[] 列表中不为空

rancher删除之后,有些namespace删除后就是这种情况.

解决办法:手动清理

  • 查看cattle-system的namespace描述
    1
    ➜  fb git:(master) kubectl get ns cattle-system  -o json > cattle.json
  • 编辑json文件,删除spec字段的内存,因为k8s集群需要认证
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ➜  fb git:(master) vim cattle-system.json

    "spec": { "finalizers": [ "kubernetes"
    ]
    },
    更改为:
    "spec": {

    },
  • 新开一个窗口运行kubectl proxy跑一个API代理在本地的8081端口
    1
    2
    ➜  ~ kubectl proxy --port=8081
    Starting to serve on 127.0.0.1:8081
  • check the status
    1
    2
    3
    ➜  fb git:(master) lsof -i:8081
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    kubectl 31323 leiyawu 3u IPv4 650617594 0t0 TCP localhost:tproxy (LISTEN)
  • 运行curl命令进行删除
    1
    ➜  fb git:(master) curl -k -H "Content-Type:application/json" -X PUT --data-binary @cattle.json http://127.0.0.1:8081/api/v1/namespaces/cattle-system/finalize
    注意:命令中的cattle.json是之前修改的json文件,cattle-system就是terminating的命名空间
  • 再次查看namespace,发现cattle-system命名空间已经消失了。
    如果出现多个命名空间无法删除的情况,循环遍历以上操作即可。
除了通过kube-proxy api来执行,也可以直接请求api server,使用kubectl replace命令(未测试):
1
kubectl replace --raw "/api/v1/namespaces/cattle-system/finalize" -f ./cattle.json

2. namespace资源对象的metadata.finalizer[] 列表不为空

比如:将集群托管到rancher管理后,rancher就会写finalizer到metadata.finalizer[] 列表,而当集群脱离rancher管理之后,手动删除namespace,往往就会发生Terminating

解决办法:

1
$ kubelet edit ns <name> #将metadata.finalizer[]列表删除

或者直接通过tke 控制台YAML编辑对应的NS

原因2:资源发现(minor)

k8s的api组织形式

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

1
2
3
4
# 查看资源
$ 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的原因
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ 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的状态
    1
    2
    3
    4
    5
    6
    7
    8
    ➜  fb git:(master) kubectl get apiservice
    NAME SERVICE AVAILABLE AGE
    v1. Local True 484d
    v1.admissionregistration.k8s.io Local True 484d
    v1.apiextensions.k8s.io Local True 484d
    v1.apps Local True 484d
    v1.authentication.k8s.io Local True 484d
    ...
  3. 将异常的apiservice状态恢复成True或者删除不需要的apiservice,即可恢复

参考文献:

https://cloud.tencent.com/developer/article/1802531
https://cloud.tencent.com/developer/article/1678604
https://medium.com/%E8%BC%95%E9%AC%86%E5%B0%8F%E5%93%81-pks%E8%88%87k8s%E7%9A%84%E9%BB%9E%E6%BB%B4/%E7%A7%BB%E9%99%A4%E8%A9%B2%E6%AD%BB%E7%9A%84terminating-namespace-c6594ebe351


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!