k8s的对象管理二(详解path与RFC7386)
概述:
根据(一)的kubectl命令可以发现,资源的更新可以是命令式的也可以是声明式的,
所谓命令式的,顾名思义就是我直接设置某个字段是什么样子的
所谓声明式的,顾名思义就是我想让某个字段是什么样子的
二者的执行对应到真正调用后端的api时是有差别的,前者是直接replace,后者则是商量着来,有可能直接replace也有可能merge(见。。。。)
所以,接下来我们一起从API的角度来探讨下replace和patch的区别
零:k8s资源更新(update)的两种方式
参考官网: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/
想对指定资源进行更新操作,API server给我们提供了两种形式的api,分别如下
1. Replace
这种方式update的目标是整个object,为整体替换。这是一个read-then-write的操作,而且因为如果在read 和 write之间资源有发生变化,那么就会发生乐观锁的失败,所以这个操作是安全的。
注: replace操作中ResourceStatus 会被系统忽略,并不会被更新,若想更新这个字段,则必须触发那些会引起该状态变化的行为才行。也就是说有,甭想通过replace命令直接更新状态,只有通过让相应的事件发生,才能间接的刷新对应的状态。
replace方式的api为:PUT /...
2. Patch
官网说:
Caution: A patch is an update operation that is scoped to specific fields of an object instead of the entire object. This enables updating only a specific set of fields on an object without reading the object first.
这种方式是对部分字段应用的一个"变更"操作,所谓的应用是指将"变更"合并到指定filed(包括primitive和complex )上,合并的过程中会根据filed类型的不同或是替换(replace),或是合并(merge).
patch操作不会引发乐观锁失败,只有最后一次写生效。如果你无法读取object的完整状态或者不希望乐观所失败,那么就推荐你使用Patch操作。
当你Patching的是复杂的类型如arrays, map,那么具体的patch是如何被应用到每个filed上的,则取决于每个字段的策略属性。
wxy:
所谓"replace"和"patch"这两种形式,首先操作的目标就是不同的的,然后他们代表的是一种结果,即当然大目标还是我们的object,细分一下也可以认为是以何种操作方式更新资源的field。最后,至于使用怎样的命令或者怎样的api参数实现这样的操作,则是另一回事。
replace:表示的是将目标当做一个整体,然后整体"替换",所以apiserver提供的API,其http method都是put;对应到我们的client-go帮我们实现的一些方法,就是“Update”接口;
patch:则是对目标的指定fields进行操作,同时指定部分还可以更加细分的进行指定的操作。至于如何进行“特定的操作,则是根据固定的策略。我们接下里就详细针对Patch操作做一个分析。其http method都是patch。
一:详解k8s的Patch操作
type Container struct { ... Ports []ContainerPort `json:"ports,omitempty" patchStrategy:"merge" patchMergeKey:"containerPort" ...` }
patchMergeKey: 用于复合结构体,其vlaue可以取值
kubectl apply如何实现
patch calculation:
官方:https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#merge-patch-calculation
last-applied-configuration这个annotation中的内容做一个计算.
- Calculate the fields to delete
对于本地配置文件中explicitly set to null的那些fields, 无论last-applied-configuration中是否存在, 那么都要Clear from the live configuration.
- Calculate the fields to set
对于本地配置文件和live configuration中都存在的字段,且值还不相同的,则以本地为准, 即Set the value in the live configuration.
last-applied-configuration
last-applied-configuration
annotation to match the value of the configuration file.1.p
二:除了缺省的"strategic merge patch",patch API还支持在调用API的时候指定type参数来决定怎么patch,具体如下
1.JSON merge patch
用法(k8s):
命令行: --type merge
API: "Content-Type:merge-patch+json"
特点:如果想要更新一个list,你的patch request中必须囊括了整个list,因为他会将行list完全替换掉旧的list
原理(RFC 7386):rfc7386 (nju.edu.cn)
2.JSON patch
用法(k8s):
命令行: --type json
API: "Content-Type:json-patch+json"
特点:如果想要更新一个list,你的patch request中必须囊括了整个list,因为他会将行list完全替换掉旧的list
原理(RFC 7386):
另外,对于缺省"strategic merge patch"方式,相当于
命令行: --type strategic
API: "Content-Type:strategic-merge-patch+json"
1.JSON Patch
这种类型的patch操作要求Patch请求以["op","path","value"]三元组的形式来定义
"op": operation,代表要执行怎样的操作,可以是"add", "remove", "replace", "move" 和 "copy"
"path":被操作对象的位置, 表示处于json文件的哪个位置的fragment,通俗的说就是json格式下的逻辑位置
"value": 用于操作的值
1)一个object的json形式描述文件如下
{ "users" : [ { "name" : "Alice" , "email" : "alice@example.org" }, { "name" : "Bob" , "email" : "bob@example.org" } ] }
2)patch请求的json形式描述如下:
[ { "op" : "replace" , ---我要做"替换"操作 "path" : "/users/0/email" , ---替换的对象是users数组的第1个元素的email字段 "value" : "alice@wonderland.org" ---要替换成的值是"alic...." }, { "op" : "add" , ---我要做"添加"操作 "path" : "/users/-" , ---增加的对象是users数组的下一级,即称为user的一个元素 "value" : { ---增加的值是一个{...} "name" : "Christine", "email" : "christine@example.org" } } ]
{ "users" : [ { "name" : "Alice" , "email" : "alice@wonderland.org" }, --被替换 { "name" : "Bob" , "email" : "bob@example.org" }, --没变 { "name" : "Christine" , "email" : "christine@example.org" } --新增的 ] }
具体工作原理用如下例子阐述:
1)一个object的json形式描述文件如下
{ "a": "b", "c": { "d": "e", "f": "g" } }
{ "a":"z", ---我想让a变成z "c": { ---我想让c的f变成null(代表删除) "f": null } }
{ "a": "z", "c": { "d": "e", } }
1.无法将值设置成null,因为在这里设置成null意味着删除
2.操作array比较麻烦,因为你必须全部写下,否则就会将旧array完全替换成新的,并不会发生"合并"
3.执行patch操作后,永远不会报错
另外,kubectl patch命令是一个直接的调用patch api的操作,即直接将patch的内容作为patch request调用api
而kubectl apply则隐含了先计算patch request的内容,然后再调用patch api