1、对于update 请求需要将整个修改后的对象提交apiserver,并且apiserver校验用户提交resourceVersion是否当前k8s中这个对象resourceVersion一致,一致才能接受本次update,否则发生版本冲突

2、对于patch请求,只需要将对象中某些字段修改提交apiserver,并且apiserver 不会考虑版本问题,而是直接将patch打到对象上,然后更新版本号
(1)json patch需要指定操作类型,且修改列表时要通过元素序号指定元素;
(2)merge patch:无法单独更新一个列表中的某个元素,会整个覆盖列表
(3)strategic merge patch更新列表时,不需要指定序号,而是以name 作为 key计算 merge,同时strategic只适用于原生 K8s 资源以及Aggregated API方式自定义资源,对于 CRD 定义的资源对象是无法使用的;

(4)apply patch:包括client-side applyserver-side applykubectl apply默认client-side apply patch,同时kubectl edit也是patch

– 首先解析用户提交数据(YAML/JSON)为一个对象 A;然后调用 Get 接口从 K8s 中查询这个资源对象:

– 如果查询结果存在kubectl 将本次用户提交数据记录到对象 A 的 annotation 中(keykubectl.kubernetes.io/lastappliedconfiguration),最后将对象 A提交给 K8s 创建

– 如果查询到 K8s 中已有这个资源,假设为对象 B,kubectl 尝试从对象 B 的 annotation 中取kubectl.kubernetes.io/lastappliedconfiguration 的值(对应了上一次 apply 提交的内容);

kubectl 根据前一次 apply 的内容和本次 apply 的内容计算diff 得到patch报文默认为 strategic merge patch 格式,如果CR则采用 merge patch,并diff添加本次的 kubectl.kubernetes.io/last-appliedconfiguration annotation最后patch 请求提交给 K8s 做更新

kubectl apply 相比,kubectl edit 逻辑上更简单一些。在用户执行kubectl edit 命令之后,kubectl 从 K8s 中查到当前的资源对象,并打开一个命令行编辑器默认vi)为用户提供编辑界面。当用户修改完成保存退出时,kubectl 并非直接把修改后的对象提交 update(避免 Conflict,如果用户修改过程中资源对象又被更新),而是会把修改后的对象和初始拿到的对象计算 diff,最后将 diff 内容用 patch 请求提交给 K8s。

server-side apply是k8s v1.18时基于managedFields的新特性计算diff得到patch报文逻辑放到服务端即kube-apiserver客户端需要提交完整managedFields即可默认为 strategic merge patch 格式,如果CR则采用 merge patch)多个client控制一个资源时, 相比于client-side applylast-applied annotations的方式server-side apply 通过一种声明式 API即managedFields来明确指定哪个Field被哪个client管理控制例如 WorkloadController只能修改image相关操作,而ScaleController 只能修改副本数。

使用 server-side apply patch 尝试着去改变一个被其他人管理字段, 会导致请求拒绝,当然也可以设置强制执行这里三种策略覆盖前值,成为唯一管理器;不覆盖前值,放弃管理权;不覆盖前值,成为共享管理器

(5)常用的three-way-merge三路合并算法的好处是程序理解你到底做了哪些改动,如果这些改动没有冲突,则它会自动帮你合并

(6)另外,kube-apply才会记录last-applied-anno上,kube-edit不会,kube-apply通过当前资源的last-applied-anno和要apply的资源计算patch

3、因此,每次对象被修改,不管是 update 还是 patch 修改,版本号metadata.resourceVersion都会发生变化,但是也要注意因为patch时apiserver不会考虑版本问题,所以如果我们 patch 之前这个对象已经被其他人修改了,那么我们的patch有可能产生非预期的后果。(metadata.generation是spec变化才会变化)

4、我们不同场景下怎么选择 update 或 patch 来使用呢?这里建议是:
如果要更新字段只有我们自己会修改(比如我们有一些自定义标签,并写了 operator管理),则使用 patch 是最简单方式
如果要更新字段可能会被其他方修改(比如我们修改的 replicas 字段可能有一些其他组件比如 HPA 也会做修改),则建议使用 update 来更新,避免出现互相覆盖;

5、对于ctrl中的几个patch封装源码目录为”sigs.k8s.io/controllerruntime/pkg/client

client.Merge:会把数据全量发送apiserver执行MergePatch;
client.Apply:会把数据全量发送到apiserver,执行server-side apply patch;
client.MergeFrom():只会发变化的部分apiserver,要用deepcopy,执行MergePatch;

6、spec和status

create只能创建metadata和spec,不能创建status
update和patch只能更新metadata和spec,不能更新status
status.update和status.patch只能更新status

原文地址:https://blog.csdn.net/qq_34562093/article/details/125703150

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_33376.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注