4

我有一个 Kubernetes自定义资源实例,我想使用 JSON 补丁通过 Kubernetes API 对其进行修补。

这是我的补丁请求:

PATCH /apis/example.com/v1alpha1/namespaces/default/mycrd/test HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
[other headers omitted for brevity...]

[
  {"op": "replace", "path": "/status/foo", value: "bar"}
]

我相当确定我的请求正文是有效的JSON 补丁,并且我之前已经使用类似的 API 调用成功更新了核心(非 CRD)API 资源。CRD 有一个openAPIV3Schema明确允许.status.foo存在和类型的定义string

上面的请求被 Kubernetes API 服务器拒绝,响应如下:

HTTP/1.1 422 Unprocessable Entity
Conent-Type: application/json
[other headers omitted for brevity...]

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "the server rejected our request due to an error in our request",
  "reason": "Invalid",
  "details": {},
  "code": 422
}

根据CRD 文档,CRD 应该支持带有内容类型PATCH的请求。application/json-patch+json但是由于某种原因,请求似乎是无效的,而 Kubernetes 没有费心告诉我为什么。API 服务器 pod 在其日志流中也没有任何相关消息。

kubectl patch在命令行上使用时也会出现同样的错误:

$ kubectl patch mycrd.example.com test --type=json -p '[{"op": "replace", "path": "/status/foo", "value": "bar"}]'   
The  "" is invalid

发生此错误的可能原因是什么?我有哪些选项可以进一步调试?

4

1 回答 1

12

在仍然输入问题的同时找到(或至少部分)答案......

Kubernetes API 服务器不会为 JSON 补丁输入递归地创建嵌套对象。此行为与RFC 6902 第 A.12 节中的 JSON Patch 规范一致:

A.12。添加到不存在的目标

一个示例目标 JSON 文档:

{ "foo": "bar" }

JSON补丁文件:

[
  { "op": "add", "path": "/baz/bat", "value": "qux" }
]

此 JSON Patch 文档应用于上述目标 JSON 文档会导致错误(因此不会应用),因为“添加”操作的目标位置既不引用文档的根,也不引用现有对象,也不是现有数组的成员。

这就是当自定义资源没有.status属性开始时原始请求失败的原因。以下两个后续调用(第二个是原始调用)将成功完成:

$ kubectl patch mycrd.example.com test --type=json \
    -p '[{"op": "replace", "path": "/status", "value": {}}]'
mycrd.example.com/test patched
$ kubectl patch mycrd.example.com test --type=json \
    -p '[{"op": "replace", "path": "/status/foo", "value": "bar"}]'
mycrd.example.com/test patched

显然,如果该属性已经包含您想要保留的数据,那么replace使用整个.status属性并不是一个好主意。{}

在这种情况下,JSON 补丁的合适替代方案是JSON 合并补丁

PATCH /apis/example.com/v1alpha1/namespaces/default/mycrd/test HTTP/1.1
Accept: application/json
Content-Type: application/merge-patch+json
[other headers omitted for brevity...]

{
  "status": {
    "foo": "bar"
  }
}

或者,或者,使用kubectl

$ kubectl patch mycrd.example.com test --type=merge \
    -p '{"status": {"foo": "bar"}}'
mycrd.example.com/test patched
于 2019-08-13T14:45:12.093 回答