和上一节类似,我们通过开启Kube Controller Manager最高级别日志,来研究这个组件的行为。在Kube Controller Manager的日志里,可以看到命名空间控制器在不断地尝试一个失败的操作,就是清理tobedeletedb这个命名空间里“收纳”的资源。
● 删除命名空间和其收纳的资源。

● 因为获取server APIs列表失败,所以不能删除命名空间。

这里我们需要理解一点,就是命名空间作为资源的“收纳盒”,其实是逻辑意义上的概念。它并不像现实中的收纳工具,可以把小的物件收纳其中。命名空间的“收纳”实际上是一种映射关系,如图15-2所示。

图15-2 命名空间与资源的关系
这一点之所以重要,是因为它直接决定了删除命名空间内部资源的方法。如果是物理意义上的“收纳”,那我们只需要删除“收纳盒”,里边的资源就一并被删除了。而对于逻辑意义上的关系,我们则需要罗列所有资源,并删除那些指向需要删除的命名空间的资源。
怎么样罗列集群中的所有资源呢,这个问题需要从集群API的组织方式说起。Kubernetes集群的API不是铁板一块,它是用分组/版本来组织的。这样做的好处显而易见,就是不同分组的API可以独立迭代,互不影响。常见的分组如apps,它有v1、v1beta1和v1beta2这三个版本。完整的分组/版本列表,可以使用kubectl api-versions命令看到。

我们创建的每一个资源,都必然属于某一个API分组/版本。以下面的Ingress为例,我们指定Ingress资源的分组/版本为networking.Kubernetes.io/v1beta1。

我们用一个简单的图来总结API分组和版本的关系,如图15-3所示。

图15-3 API分组和版本
实际上,集群有很多API分组/版本,每个API分组/版本支持特定的资源类型。我们通过Yaml编排资源时,需要指定资源类型(kind),以及API分组/版本(apiVersion)。而要列出资源,我们需要获取API分组/版本的列表。
理解了API分组/版本的概念之后,再回头看Kube Controller Manager的日志,就会豁然开朗。显然命名空间的Controller在尝试获取API分组/版本列表,当遇到metrics.Kubernetes.io/v1beta1的时候,查询失败了,并且查询失败的原因是“the server is currently unable to handle the request”。