client-go MergePatch 或 StragegyMergePatch for map type 字段的合并逻辑是什么?

What is the merge logic of client-go MergePatch or StragegyMergePatch for map type field?

MergePatch 或 StragegyMergePatch 在修补地图类型字段(如标签)时做什么?

当我使用MergePatch 或StragegyMergePatch 时,如果我在yaml 文件中添加一些标签,然后将整个yaml 文件的数据传输到patch 方法,它可以工作。但是如果我从 yaml 文件中删除一些标签,然后打补丁,它就不起作用了。

我已经进行了进一步调查,很多事情都取决于您想在哪个 resource 上做什么。文档可能难以理解,所以我将在这个答案中对其进行更多扩展。

背景

您指的是 Merge Patch where you have example of merge patching (adding additional container) spec.template.spec.containers. Below you have Notes on the strategic merge patch

The patch you did in the preceding exercise is called a strategic merge patch. Notice that the patch did not replace the containers list. Instead it added a new Container to the list. In other words, the list in the patch was merged with the existing list. This is not always what happens when you use a strategic merge patch on a list. In some cases, the list is replaced, not merged.

With a strategic merge patch, a list is either replaced or merged depending on its patch strategy. The patch strategy is specified by the value of the patchStrategy key in a field tag in the Kubernetes source code.

默认补丁策略可以在Kubernetes API documentation或Kubernetes源代码

中找到

关于修补 Deployments labels,因为 apiVersion: apps/v1 这是不可能的。您可以在 Deployments - Label selector updates.

中找到确认信息

Note: In API version apps/v1, a Deployment's label selector is immutable after it gets created.

如果您在 apiVersion: apps/v1 中尝试 updatepatch,您将收到 field is immutable 错误。更改 labels/selectors 的唯一方法是重新部署整个 Deployment.

但是,如果您要使用具有 apiVersion: extensions/v1beta1 的旧 Kubernetes 版本,则可以像 Github example 中那样对其进行修补。

请记住,您还可以使用更多 patching methods,例如 JSON merge patchmerge patch using the retainKeys strategy

测试

基于Documentation Deployment Example.

您不能更改 apiVersion: apps/v1 中的 Deployment 标签,因此您也不能 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 的评论中,可以像 中那样进行修补。

在文档 Use a strategic merge patch to update a Deployment 中,您可以找到 2 个示例,container 其中 patchStrategy:"merge":

The patch strategy is specified by the value of the patchStrategy key in a field tag in the Kubernetes source code. For example, the Containers field of PodSpec struct has a patchStrategy of merge:

type PodSpec struct {
  ...
  Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`

tolerationspatchStrategy 字段的示例。

Notice that the tolerations list in the PodSpec was replaced, not merged. This is because the Tolerations field of PodSpec does not have a patchStrategy key in its field tag. So the strategic merge patch uses the default patch strategy, which is replace.

type PodSpec struct {
  ...
  Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`

两个示例(包含容器和容差)都是列表,但不同之处在于当您使用合并时它会添加新的,但是当您要替换时,key 值必须相同。

补丁-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 中更改它们。基于 Docs 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

The patch strategy is specified by the value of the patchStrategy key in a field tag in the Kubernetes source code.

merge补丁中所有信息都是混合的,当使用replace补丁时,新旧补丁对象必须具有相同的key

您可以使用几种补丁方法:

In other words, the list in the patch was merged with the existing list.

A strategic merge patch is different from a JSON merge patch. With a JSON merge patch, if you want to update a list, you have to specify the entire new list. And the new list completely replaces the existing list.

如果这没有回答您的问题,请说明您想要使用哪个版本、资源和您想要修补的内容来实现。