K8s Patch

为什么要有 patch ?

K8s 使用乐观锁管理数据,当使用 update 更新资源对象的时候必须带上 resourceVersion ,这就需要先从 K8s 获取到最新的资源信息,修改字段后再提交给 K8s。如果 apiserver 发现版本比当前存的版本落后就会更新失败。patch 就没有这个问题,可以指定字段立即更新。

Patch 操作的 3 种类型

执行 kubectl patch 命令时 --type 共有三个可选值,strategic 为默认值,其余还有 jsonmerge

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 表达规范来执行修改操作。

如下示例会针对 deployment 里的 pod 增加 hostIPC 字段为 true。

[{
    "op": "add",
    "path": "/spec/template/spec/hostIPC",
    "value": true
}]

对比与思考

patch 的三种方法各有优劣:

© 2022 - 2025 · Stay foolish · Theme Simpleness Powered by Hugo ·