kubernetes - client-go MergePatch或StrategyMergePatch对于 map 类型字段的合并逻辑是什么?

标签 kubernetes client-go

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

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

最佳答案

我进行了进一步调查,许多事情取决于您到底想对哪个资源执行什么操作。文档可能很难理解,因此我将在这个答案中对其进行更多扩展。

背景

您指的是Merge Patch其中有合并修补(添加附加容器)spec.template.spec.containers 的示例。下面有 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 源代码中

关于修补部署标签,因为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更新修补它,您将得到一个字段是不可变的 错误。更改标签/选择器的唯一方法是重新部署整个部署

但是,如果您将旧版 Kubernetes 与 apiVersion:extensions/v1beta1 一起使用,则可以像 Github example 那样进行修补。 .

请记住,您还可以使用更多修补方法,例如JSON合并修补使用retainKeys策略的合并修补.

测试

基于Documentation Deployment Example .

您无法更改 apiVersion: apps/v1 中的 Deployment 标签,因此您也无法修补它。

$ 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

在评论中,您提到了节点选择器,它可以像 this stackoverflow thread 中那样进行修补。 .

在文档中 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" ...`

tolerations 示例,其中空 patchStrategy 字段。

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 值必须相同。

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

它仅替换具有相同的值。如果您将 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:

结论

您无法更改部署标签,因为这些字段是不可变的。

当您想要修补某些内容时,您必须检查哪个是默认的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.

如果这没有回答您的问题,请具体说明您想要使用哪个版本、资源以及要修补的内容来准确实现什么。

关于kubernetes - client-go MergePatch或StrategyMergePatch对于 map 类型字段的合并逻辑是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65820515/

相关文章:

kubernetes - Helm charts vs ansible-playbook vs k8s operator 在系统安装中

kubernetes - 为已部署的 Kubernetes 服务获取 YAML?

go - 如何在golang程序中使用client-go列出k8s集群中的所有Pod?

kubernetes - 如何使用 client-go API 返回的 Pod 条件数组?

kubernetes - Go mod 下载提示构建限制

go - 如何使用kubernetes client-go将文件复制到容器?

kubernetes - 如何部署没有死锁的Pod初始化程序?

amazon-ec2 - 在 aws 上使用弹性 IP 地址公开 kubernetes 服务

kubernetes - --pod-infra-container-image 是什么意思?

kubernetes - 使用 k8s client-go 滚动更新