如何解决地图类型字段的客户端 MergePatch 或 StragegyMergePatch 的合并逻辑是什么? 背景测试结论
在修补地图类型字段(如标签)时,MergePatch 或 StragegyMergePatch 会做什么?
当我使用MergePatch或StragegyMergePatch时,如果我在yaml文件中添加一些标签,然后将整个yaml文件的数据传输到patch方法,它可以工作。但是如果我从 yaml 文件中删除一些标签,然后打补丁,它就不起作用了。
请原谅我糟糕的英语。
解决方法
我进行了进一步调查,很多事情取决于您究竟想在哪个 resource
上执行。文档可能难以理解,因此我将在此答案中对其进行更多扩展。
背景
您指的是 Merge Patch,其中有合并修补示例(添加额外容器)spec.template.spec.containers
。下面是Notes on the strategic merge patch。
您在前面练习中所做的补丁称为战略合并补丁。请注意,补丁没有替换容器列表。相反,它向列表中添加了一个新的 Container。换句话说,补丁中的列表与现有列表合并。当您在列表上使用战略合并补丁时,并不总是会发生这种情况。在某些情况下,列表会被替换,而不是合并。
对于战略合并补丁,列表将根据其补丁策略被替换或合并。补丁策略由 Kubernetes 源代码中的字段标签中的 patchStrategy 键的值指定。
可以在 Kubernetes API documentation 或 Kubernetes 源代码中找到默认补丁策略
关于修补 Deployments labels
,因为 apiVersion: apps/v1
这是不可能的。您可以在 Deployments - Label selector updates 中找到确认信息。
注意:在 API 版本 apps/v1 中,Deployment 的标签选择器在创建后是不可变的。
如果您尝试在 update
中 patch
或 apiVersion: apps/v1
它,您将收到 field is immutable
错误。更改 labels/selectors
的唯一方法是重新部署整个 Deployment
。
但是,如果您将旧 Kubernetes 版本与 apiVersion: extensions/v1beta1
一起使用,则可以像在 Github example 中那样进行修补。
请记住,您还可以使用更多的 patching methods
,例如 JSON merge patch
或 merge patch using the retainKeys strategy
。
测试
基于Documentation Deployment Example。
您不能更改 Deployment
中的 apiVersion: apps/v1
标签,因此您也不能patch
。
$ kubectl apply -f nginx-second.yaml
The Deployment "nginx-deployment" is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{"app":"nginx","test":"test"},MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable
您在评论中提到了 Node Selector
,它可以像 this stackoverflow thread 一样进行修补。
在文档 Use a strategic merge patch to update a Deployment 中,您可以找到 2 个示例,container
其中 patchStrategy:"merge"
:
补丁策略由 Kubernetes 源代码中的字段标签中的 patchStrategy 键的值指定。比如PodSpec结构体的Containers字段有一个patchStrategy为merge:
type PodSpec struct {
...
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
和 tolerations
示例,其中 patchStrategy
字段为空。
注意 PodSpec 中的容忍列表被替换,而不是合并。这是因为 PodSpec 的 Tolerations 字段在其字段标签中没有 patchStrategy 键。所以策略合并补丁使用默认补丁策略,即替换。
type PodSpec struct {
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
两个示例(包含容器和容忍)都是列表,但不同之处在于当您使用合并时,它会添加新的,而当您想要替换时,key
值必须相同。
patch-tolerations.yaml
$ cat patch-tolerations.yaml
spec:
template:
spec:
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
test1: testvalue1
test2: testvalue2
test3: testvalue3
使用相同的键替换
$ kubectl get deploy patch-demo -o yaml | grep tolerations: -A 5
tolerations:
- effect: NoSchedule
key: dedicated
value: test-team
$ kubectl patch deployment patch-demo --patch "$(cat patch-tolerations.yaml)"
$ kubectl get deploy patch-demo -o yaml | grep tolerations: -A 5
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
它只替换了具有相同 key
的值。如果您将 patch-tolerations.yaml
更改为
spec:
template:
spec:
tolerations:
- effect: NoSchedule
test1: testvalue1
test2: testvalue2
test3: testvalue3
你会得到一个错误:
$ kubectl patch deployment patch-demo --patch "$(cat patch-tolerations.yaml)"
The Deployment "patch-demo" is invalid: spec.template.spec.tolerations[0].operator: Invalid value: "": operator must be Exists when `key` is empty,which means "match all value
s and all keys"
StatefulSet 上的测试
当您询问标签时,您可以在 statefulset
中更改它们。基于文档 Creating a StatefulSet 中的示例,带有一些附加注释 metadata.labels
。
$ kubectl get sts -oyaml | grep labels: -A 3
labels:
test: test
test1: test1
name: web
--
labels:
app: nginx
spec:
containers:
---
$ cat patch-sts.yaml
metadata:
labels:
run: runtest
app: apptest
$ cat patch-sts-template.yaml
spec:
template:
metadata:
labels:
app: nginx
app2: run
test: test
---
$ kubectl patch sts web --patch "$(cat patch-sts.yaml)"
statefulset.apps/web patched
$ kubectl patch sts web --patch "$(cat patch-sts-template.yaml)"
statefulset.apps/web patched
$ kubectl get sts -oyaml | grep labels: -A 5
labels:
app: apptest
run: runtest
test: test
test1: test1
name: web
--
labels:
app: nginx
app2: run
test: test
spec:
containers:
结论
您无法更改 Deployment labels
,因为这些字段是不可变的。
当你想要修补某些东西时,你必须检查哪个是默认的 patchStrategy
。
补丁策略由 Kubernetes 源代码中的字段标签中的 patchStrategy 键的值指定。
在merge
补丁中所有信息都是混合的,使用replace
补丁时,新旧补丁对象必须具有相同的key
。
您可以使用一些补丁方法:
换句话说,补丁中的列表与现有列表合并。
战略合并补丁不同于 JSON 合并补丁。使用 JSON 合并补丁,如果要更新列表,则必须指定整个新列表。并且新列表完全替换了现有列表。
如果这没有回答您的问题,请具体说明您想要使用哪个版本、资源和您想要修补的内容来准确实现什么。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。