K8s Patch
为什么要有 patch ?
K8s 使用乐观锁管理数据,当使用 update 更新资源对象的时候必须带上 resourceVersion
,这就需要先从 K8s 获取到最新的资源信息,修改字段后再提交给 K8s。如果 apiserver 发现版本比当前存的版本落后就会更新失败。patch 就没有这个问题,可以指定字段立即更新。
Patch 操作的 3 种类型
执行 kubectl patch 命令时 --type
共有三个可选值,strategic
为默认值,其余还有 json
、merge
。
Parameter Value | Merge Type |
---|---|
json |
JSON Patch, RFC 6902 |
merge |
JSON Merge Patch, RFC 7386 |
strategic |
Strategic Merge Patch |
1. Strategic merge patch (不支持自定义资源)
strategic 是默认的 patch 类型,通过命令行操作比较简单:写一个 YAML 指明要更新的字段然后执行即可。例如更新一个 deployment:
kubectl patch deploy patch-demo --patch-file patch-file.yaml
。最终行为结果是 replace 还是 merge 取决于被更新字段对 patch 行为的默认定义。
spec:
template:
spec:
containers:
- name: patch-demo-ctr
image: uhub.service.ucloud.cn/library/redis:2.8.8
比如 pod.spec.containers
的 patch 策略是 merge , patchMergeKey
为 name,上面这个 patch-file.yaml 提交后会针对 image name 为 patch-demo-ctr 的 container 项做合并。如果 patch-demo-ctr 的 container 不存在,则插入新的 container 到 containers List。Tolerations 字段没有 patchStrategy
tag ,所以其默认 patch 策略是 replace,直接做替换。
type PodSpec struct {
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name"
...
}
2. JSON Merge Patch
处理方式参照 RFC7386 ,大致思路就是:使用当前指定的字段替换原字段。比如下面这个 YAML ,将直接覆盖 containers 字段。
spec:
template:
spec:
containers:
- name: patch-demo-ctr-3
image: gcr.io/google-samples/hello-app:2.0
如果想删除一个字段的话,指定 value 为 null
即可,比如删除 deployment 内 pod 的 hostIPC 字段(patch file 也可以是 JSON 格式)。
{"spec":{"template":{"spec":{"hostIPC":null}}}}
3. JSON Patch
处理方式参照 RFC6902,会按照指定的 JSON 表达规范来执行修改操作。
- op: 可选值包括 add,remove,replace,move,test,copy
- path: 指定要更新的字段,字段层级间使用
/
分隔 - value: 要更新的目标值
如下示例会针对 deployment 里的 pod 增加 hostIPC 字段为 true。
[{
"op": "add",
"path": "/spec/template/spec/hostIPC",
"value": true
}]
对比与思考
patch 的三种方法各有优劣:
- 如果比较明确的要修改、删除特定字段,则 JSON Patch 最好,因为其可读性很高,写在代码里十分清晰易懂。
- 如果要局部替换,则 JSON Merge Patch 最简单直接
- 如果对多个值做修改,则 strategic merge patch 好用,因为一些字段(比如 containers)支持 patchMergeKey,可以做到修改数组内指定元素的字段。