Custom `Namespace` cluster wide resource reports 404 when trying to GET
提问者定义的CRD配置文件是这样的
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
creationTimestamp: null
name: namespaces.test.my.domain
spec:
group: test.my.domain
names:
kind: Namespace
listKind: NamespaceList
plural: namespaces
singular: namespace
scope: Cluster
versions:
- name: v1beta1
schema:
openAPIV3Schema:
description: Test is the Schema for the tests API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: TestSpec defines the desired state of Test
properties:
foo:
description: Foo is an example field of Test. Edit Test_types.go to
remove/update
type: string
type: object
status:
description: TestStatus defines the observed state of Test
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
他把自己定义的资源 kind 就设置为了 namespace。资源的复数形式就是 namespaces,然后启动了一个名为 namespace-sample 的实例。
比如我们随便启动一个
apiVersion: test.my.domain/v1beta1
kind: Namespace
metadata:
name: namespace-sample
然后使用以下命令获取资源:
kubectl get namespaces.test.my.domain namespace-sample
会报出错误。调整一下日志等级,在命令后面添加 --v=6,接着去查看 kubectl 的日志输出,有一个资源请求的时候出问题了。
GET https://10.20.9.140:6443/apis/test.my.domain/v1beta1/namespaces/namespace-sample 404 Not Found in 2 milliseconds
"metadata": {},
"status": "Failure",
"message": "the server could not find the requested resource (get namespaces.test.my.domain namespace-sample)",
"reason": "NotFound",
"details": {
"name": "namespace-sample",
"group": "test.my.domain",
"kind": "namespaces",
"causes": [
{
"reason": "UnexpectedServerResponse",
"message": "404 page not found"
}
]
}
"code": 404
出问题的地方应该是这个文件
kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go 中的 NewRequestInfo 方法(line:117)
在kubernetes中,使用 get 获取 CRD 的 url 规则是这样的:
apis/<group_name>/<version>/<resourceName>/<subresource>
对应到日志里面实际报错的信息 URL 是这样的:
/apis/test.my.domain/v1beta1/namespaces/namespace-sample
但是,kubernetes 中还有其他的 URL 规则,比如获取一些内置资源的 URL 是这样的:
需要注意的是,红框里面的 namespaces 这个是写死的,不可变的。
既然 kubectl 请求这个 URL 出了问题,我们按照 url=/apis/test.my.domain/v1beta1/namespaces/namespace-sample
走一下代码流程:
到这里,URL 前面的几个参数都被分离了出去,还剩下 资源名字 和 资源实例。现在 currentParts=["namespaces", "namespace-sample"]
接着往下走,到了这一步:
如果走了这个 if 分值的话,下面就会接着把 namespace-sample 分配给 requestInfo.Namespace,这明显是错误的。
获取 CRD 不应该走上面的 if 分支,而要走下面的这个判断
所以我觉得最大的问题还是为什么要把 CRD 的名字设置为 namespace,那么可以使得这种情况不 panic 吗?应该是可以的,但是目前来看是有点难。URL 的匹配规则比较复杂,这种冲突要解决的话还得仔细想想怎么不影响现有的规则。
但是,我觉得最简单的办法就是不要使用 namespace 做资源的 kind,本来这种命名就让人十分的困惑。
目前来看应该确实是这样导致的,比如我们什么都不改,只是把上述 crd 的 yaml 文件中 spec.plural
改为 namespacess
,在原本的后面多加一个 s,自然我们的 metadata.name
也就变成了namespacess.test.my.domain
,然后在执行相同的操作。
这次在获取资源的时候就不会报错了。