kubernetes issue查看解决经历0

issue地址:https://github.com/kubernetes/kubernetes/issues/97423
issue描述:提问者创建了一个 crd,并且使用该 crd 实例化了一个 resource,都没问题,但是在使用 patch 更新 resource 的时候报了一个错误:

$ kubectl patch --type=strategic xxxx(crd group) xxxx(resource name) -p '{"metadata":{"finalizers": ["sample.acnodal.io/fooFinalizer"]}}'
Error from server (UnsupportedMediaType): the body of the request was in an unknown format - accepted media types include: application/json-patch+json, application/merge-patch+json, application/apply-patch+yaml

为什么使用 patch 更新 crd 会有这个错误,这个错误的提示再告诉我 系统支持 json,yaml 等格式,当前使用的是不受支持的类型,但这明明就是 标准的 json 数据呀,怎么会不支持呢,问了身边的同事,他们也觉得这应该是个错误,命令没问题,虽然不知道实际是什么错误,这个报错和实际错误应该是不对应的。恰好我也是这么想的,
然后我去源代码里面看了看,为什么会报出这个错误。

这个错误应该是 kube-apiserver 返回的,首先就去 apiserver 里面看看,到底是怎么样的,apiserver 处理逻辑:

# kubernetes 处理 crd 的主要逻辑代码:
# /data/gopath/src/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go 
# 入口函数 function:ServeHTTP,line:233
# customresource_handler文件里的ServeHTTP方法里面,第 368 行,
case len(subresource) == 0:
    handlerFunc = r.serveResource(w, req, requestInfo, crdInfo, terminating, supportedTypes)
# crd.yaml 文件里面确实没有 subresource 字段,应该会进到这个分支里面
# 然后在 serveResource 方法里面看代码,我们使用的是 patch 方法,应该会走下面(line:408)的代码:
case "patch":
    return handlers.PatchResource(storage, requestScope, r.admission, supportedTypes)
# 然后跳转到 /data/gopath/src/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/patch.go 文件中的 PatchResource 函数
# 最终在这一步抛出了问题(line:82):
// Ensure the patchType is one we support
if !sets.NewString(patchTypes...).Has(contentType) {
    scope.err(negotiation.NewUnsupportedMediaTypeError(patchTypes), w, req)
    return
}

到这里,算是吧apiserver流程梳理明白了,就是因为最后一部里面的 patchTypes 没有包含 kubectl 上传的 contentType 才出现的这个问题。

那么有必要看看这个 patchTypes 里面都有些什么,最终,在 /data/gopath/src/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go 里面找到了(line:345),这个 supportedTypes 就是后续使用的 patchTypes 原型

supportedTypes := []string{
    string(types.JSONPatchType),
    string(types.MergePatchType),
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
    supportedTypes = append(supportedTypes, string(types.ApplyPatchType))
}

在代码里面能看到一共添加了三个类型, application/json-patch+json ;application/merge-patch+json ;application/apply-patch+yaml

整个流程看下来并没有什么问题,那么,是 kubectl 发送了其他的 headers 吗?还得在看看 kubectl 执行的具体过程,可 kubectl 就是个命令行工具,怎么调试呢,
最终发现了在执行命令的时候后面加上 --v 可以查看非常详细而具体的信息。然后发现了这几行日志输出:

PATCH https://x.x.x.x:6443/apis/samplecontroller.k8s.io/v1alpha1/namespaces/default/foos/example-foo?fieldManager=kubectl-patch
Request Headers:
     Accept: application/json
     Content-Type: application/strategic-merge-patch+json
     User-Agent: kubectl/v1.20.0 (linux/amd64) kubernetes/af46c47

可以看到实际发送的是 application/strategic-merge-patch+json,并不包括代码里注册的三个类型。
原来真的是 kubectl 发送了不支持的数据类型导致的,后面去查了一下相关说明:

kubernetes 的 crd 资源不支持使用 --type=strategic 去更新,就算不带这个 flag,他默认就是 strategic 模式,所以在涉及到 crd 的时候,必须要显示的声明
--type=mrege 才行。归根结底还是提问者的使用方法有误,这并不是一个 bug。

然后再去看这个问题,才注意到有人在下面回复过这么一句话:

When you run it with --dry-run=client, it suggests to use --type=merge and it works.

当时我没注意到这句话,总觉得实际输入就是 json ,为什么会报这个错误,现在看完源码之后,恍然大悟,明白了回复者在说什么。原先我竟然还固执的觉得这应该是个 bug。

总结:对于 kubernetes 了解不深,如果对于系统使用很熟练的话,应该马上就能察觉到 crd 不支持 strategic 合并策略,然后明白这个是提问者本身的问题。
对返回的错误信息看的也是懵懵懂懂,才会觉得这不是正常的现象。

上一篇:How To Solve Autel Scanner “Network Busy” Issue


下一篇:Excelize 2.3.2 发布,Go 语言 Excel 文档基础库,2021 年首个更新