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 apply和server-side apply,kubectl apply时默认是client-side apply patch,同时kubectl edit也是patch;
– 首先解析用户提交的数据(YAML/JSON)为一个对象 A;然后调用 Get 接口从 K8s 中查询这个资源对象:
– 如果查询结果不存在,kubectl 将本次用户提交的数据记录到对象 A 的 annotation 中(key 为 kubectl.kubernetes.io/last–applied–configuration),最后将对象 A提交给 K8s 创建;
– 如果查询到 K8s 中已有这个资源,假设为对象 B,kubectl 尝试从对象 B 的 annotation 中取出 kubectl.kubernetes.io/last–applied–configuration 的值(对应了上一次 apply 提交的内容);
– kubectl 根据前一次 apply 的内容和本次 apply 的内容计算出 diff 得到patch报文(默认为 strategic merge patch 格式,如果CR则采用 merge patch),并将 diff 中添加本次的 kubectl.kubernetes.io/last-applied–configuration 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 apply 用 last-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/controller–runtime/pkg/client“
– client.Merge:会把数据全量发送到apiserver,执行MergePatch;
– client.Apply:会把数据全量发送到apiserver,执行server-side apply patch;
– client.MergeFrom():只会发变化的部分到apiserver,要用deepcopy,执行MergePatch;
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进行投诉反馈,一经查实,立即删除!