- 序言
- JSON Patch
- JSON Merge Patch
- JSON Patch 與 JSON Merge Patch 對比
- Strategic Merge Patch
- 總結(jié)
- 參考
序言
在更新 k8s 資源的時候,除了 update 這種方式讥珍,k8s 也提供了 patch 來進(jìn)行資源的更新誉券。
通過 kubectl patch 來更新的時候策州,也提供了不同的更新方式
這里的三種方式對應(yīng)的就是 JSON Patch诞丽、JSON Merge Patch 以及 k8s 自定義的 Strategic Merge Patch鹉勒。
今天我們來看下這三種方式分別都是怎么工作的磅轻,讓大家能有一個大概的認(rèn)識珍逸,在選擇方案的時候,能有所幫助聋溜。
因為 Json Patch 和 Json Merge Patch 大家在其他的很多地方也會用到谆膳,因此使用場景會更多,所以會優(yōu)先講解這兩種方式撮躁,我也建議大家先搞懂這兩種方式漱病。
Strategic Merge Patch 只有在更新 k8s 的標(biāo)準(zhǔn)資源的時候才會有(截止今天,不支持自定義資源通過這種方式進(jìn)行更新)把曼,因此放在最后講解杨帽。
Json Patch
Json Patch 是一種比較好理解的方式,當(dāng)你更新 json 文檔的時候嗤军,你可以通過直接指定 'op' 'path' 'value' 來完成注盈,比如如下 patch 數(shù)據(jù)。op 代表了執(zhí)行的操作類型(目前在 RFC 文檔中指定了有六種叙赚,分別是 add老客、remove 、replace震叮、move沿量、copy、test冤荆,具體的可以參見 Json Patch RFC 文檔)朴则,path 指定了你要更新的 key 值,value 代表了被更新后的值。
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]
我們來看個示例乌妒。
比如原來的 json 數(shù)據(jù)如下:
{
"title": "Goodbye!",
"author": {
"givenName": "John",
"familyName": "Doe"
},
"tags": [
"example",
"sample"
],
"content": "This will be unchanged"
通過 JSON Patch 格式來 patch 以下數(shù)據(jù)
[
{ "op": "replace", "path": "/title", "value": "Hello!"},
{ "op": "remove", "path": "/author/familyName"},
{ "op": "add", "path": "/phoneNumber", "value": "+01-123-456-7890"},
{ "op": "replace", "path": "/tags", "value": ["example"]}
]
就會最終變成以下信息
{
"title": "Hello!",
"author": {
"givenName": "John"
},
"tags": [
"example"
],
"content": "This will be unchanged",
"phoneNumber": "+01-123-456-7890"
}
我們可以對比下兩者之間的差別
可以明顯看出汹想,在 JSON Patch 格式數(shù)據(jù)中對應(yīng)的 remove、replace 以及 add 都在對應(yīng)源 json 文件的位置產(chǎn)生了變化撤蚊。
JSON Merge Patch
如果說 Json Patch 是一系列操作的集合古掏,那么 Json Merge Patch 就是一系列差異的集合。差異就是指 原始 Json 文件 和 目標(biāo) Json 文件 的不同侦啸。
如果是刪除某個字段槽唾,則需要將字段置為 null,如果是修改某個字段光涂,則需要將新的 value 值寫在 對應(yīng)的 key 上庞萍。
比如為了達(dá)到和上面示例類似的效果,通過 Json Merge Patch 在執(zhí)行操作的時候忘闻,對應(yīng)的數(shù)據(jù)如下钝计。
{
"title": "Hello!",
"author": {
"familyName": null
},
"phoneNumber": "+01-123-456-7890",
"tags": [
"example"
]
}
可以看到這里修改了 title 的值,去掉了 author 中的 familyName齐佳,增加了 phoneNumber 以及刪除了 tags 中的 sample私恬。通過這種方式也達(dá)到了相同的結(jié)果。詳細(xì)內(nèi)容亦可參考 JSON Merge Patch RFC 文檔炼吴。
JSON Patch 與 JSON Merge Patch 對比
就我的使用體驗而言本鸣,他們在常規(guī)的使用情況下不分伯仲,但在一些特殊場景場景硅蹦,都會存在一些難以解決的問題荣德。
Json Patch 因為是操作的集合,在并發(fā)的這種場景下提针,有可能就會造成 某個數(shù)組中的值,被增加了多次這種問題曹傀,反觀 Json Merge Patch辐脖,因為它提供的數(shù)組是完整的數(shù)組,因為不會有該問題皆愉。
當(dāng)然 Json Merge Patch 也不是萬能的嗜价,只要觀察示例中使用的文件,就不難發(fā)現(xiàn) Json Merge Patch 存在一些致命的限制幕庐。
- 刪除某個鍵值久锥,需要在 patch 文件中將對應(yīng)的值置成 null,但是如果我們某個值异剥,確實是需要置成 null瑟由,那就幾乎無解了
- 數(shù)組需要提供全量的,在很多場景下冤寿,這個是有些讓人難以接受歹苦,比如只有一個很細(xì)小的值青伤,也是需要 提供全量的數(shù)組
- 不會報錯,無論什么情況殴瘦,都會 patch 成功狠角。在真實使用場景下,還需要做額外的校驗
當(dāng)然在實際場景中蚪腋,我們可以根據(jù)自己的使用場景靈活的來確定使用哪種方式丰歌。
Strategic Merge Patch
這種方式是更新 k8s 資源時,提供的一種特殊的新的類型屉凯,并不是一個標(biāo)準(zhǔn)的協(xié)議立帖。
這種方式其實是基于 JSON Merge Patch 的理念來實現(xiàn)的,但是又可以避免 Json Merge Patch 中的坑神得。比如上面提到的修改數(shù)組需要提供全量數(shù)組的問題厘惦,示例如下。
當(dāng)前集群有一個 deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: patch-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: patch-demo-ctr
image: nginx
tolerations:
- effect: NoSchedule
key: dedicated
value: test-team
我們想給這個 deployment 增加一個容器哩簿,這個時候我們創(chuàng)建一個 patch 文件
spec:
template:
spec:
containers:
- name: patch-demo-ctr-2
image: redis
執(zhí)行命令宵蕉,進(jìn)行 patch 操作,
kubectl patch deployment patch-demo --patch "$(cat patch-file-containers.yaml)"
這個時候节榜,再去查看對應(yīng)的 deployment 就會包括 patch 文件中的容器
containers:
- image: redis
imagePullPolicy: Always
name: patch-demo-ctr-2
...
- image: nginx
imagePullPolicy: Always
name: patch-demo-ctr
...
我們在上面的操作中所做的 patch 稱為策略性合并 patch(Strategic Merge Patch)羡玛。 在這種情況下,patch 中的列表與現(xiàn)有列表合并宗苍。但是當(dāng)你在列表中使用策略性合并 patch 時稼稿,在某些情況下,列表是替換的讳窟,而不是合并的让歼。
patch 策略由 Kubernetes 源代碼中字段標(biāo)記中的 patchStrategy 鍵的值指定。 例如丽啡,PodSpec 結(jié)構(gòu)體的 Containers 字段的 patchStrategy 為 merge谋右,因此這里的操作是一個合并的操作
type PodSpec struct {
...
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
如果我們替換 deployment 中另外一個列表數(shù)據(jù),你就會發(fā)現(xiàn)不同补箍。
template:
spec:
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
執(zhí)行命令改执,將該文件內(nèi)容 patch 到 deployment 中。
kubectl patch deployment patch-demo --patch "$(cat patch-file-containers.yaml)"
we will get that in deployment
...
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
...
請注意坑雅,PodSpec 中的 tolerations 列表被替換辈挂,而不是合并。這是因為 PodSpec 的 tolerations 的字段標(biāo)簽中沒有 patchStrategy 鍵裹粤。所以策略合并 patch 操作使用默認(rèn)的 patch 策略终蒂,也就是 replace。
type PodSpec struct {
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
總結(jié)
標(biāo)題雖然是 k8s patch 的幾種方式,但是主要還是分析了下 JSON Patch 和 JSON Merge Patch 的不同后豫,因為 k8s 的 Strategy Merge Patch 幾乎就是 JSON Merge Patch 的一個變種悉尾,搞懂了前兩種方式,這種方式也就很容易弄清楚了挫酿。
參考
json patch
json merge patch
Json Patch and Json Merge Patch — Quick Example in Java
JSON Patch and JSON Merge Patch
Update API Objects in Place Using kubectl patch