由来
今天在折腾 admission webhook 注入一些属性的时候遇到了 Error from server (InternalError): error when creating "xxx.yml": Internal error occurred: jsonpatch add operation does not apply: doc is missing path: "/spec/template/spec/dnsConfig/options"
。折腾半天才发现在代码里使用 jsonPatch 的话不能直接绕过结构体实例去 patch。
排查过程
WebHook 接收和响应都是一个 AdmissionReview 对象,请求是里面的 AdmissionRequest,响应是里面的 AdmissionResponse。
比如说我们创建了个 MutatingWebhookConfiguration
指定让 apps/v1
的 deploy
传到我们的 webhook, 我们要修改 deploy 的一些属性,我个人是增加 dns 的 single-request-reopen
的属性的,得在 AdmissionResponse
里传一个 jsonPatch的切片。
代码里这块是:
1 | type patchOperation struct { |
后面发现创建 deploy 就报开头的错误。然后日志里打印了下:
1 | apiVersion:apps/v1 resource: default/nginx-deployment, AdmissionResponse: patch=[{"op":"replace","path":"/spec/template/spec/dnsConfig/options","value":[{"name":"single-request-reopen"}]}] |
然后把这个 patch 在 kubectl 上测试了下是可以的:
1 | kubectl -n kube-system patch deployments tiller-deploy --type=json -p='[{"op":"add","path":"/spec/template/spec/dnsConfig/options","value":[{"name":"single-request-reopen"}]}]' |
刚开始把 kube-apiserver 开 -v=8 发现 panic的信息,然后升了下版本还是没用。然后在源码里找了下这个报错:
1 | find -type f -name '*.go' -exec grep -l 'replace operation does not apply: doc is missing path' {} \; |
发现这个错误是引入的库抛出来的,和 k8s 无关,想了下后换个 key 试试看。
1 | { |
发现后面 command
这个也不行,explain 看了下,试试上层的看看:
1 | for i := range deployment.Spec.Template.Spec.Containers { |
发现可以,应该是得给一个嵌套的结构体实例,而不是直接绕过这个结构体,去 patch
里面属性的 value
,换下前面的 dnsConfig 试试:
1 | { |
发现也可以了。