首页 > 解决方案 > 地图类型字段的客户端合并逻辑是什么?

问题描述

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

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

标签: kubernetesclient-go

解决方案


我已经进一步调查,很多事情取决于你到底想做什么resource。文档可能很难理解,因此我将在此答案中对其进行更多扩展。

背景

您指的是合并补丁,其中有合并补丁的示例(添加额外的容器)spec.template.spec.containers。下面你有关于战略合并补丁的注释

您在前面的练习中所做的补丁称为战略合并补丁。请注意,补丁没有替换容器列表。相反,它在列表中添加了一个新容器。换句话说,补丁中的列表与现有列表合并。当您在列表上使用战略合并补丁时,这并不总是会发生。在某些情况下,列表会被替换,而不是合并。

使用战略合并补丁,列表被替换或合并取决于其补丁策略。补丁策略由 Kubernetes 源代码中字段标签中的 patchStrategy 键的值指定。

默认补丁策略可以在Kubernetes API 文档或 Kubernetes 源代码中找到

关于补丁Deployments labels,因为apiVersion: apps/v1这是不可能的。您可以在Deployments-Label selector updates中找到确认信息。

注意:在 API 版本 apps/v1 中,Deployment 的标签选择器在创建后是不可变的。

如果您尝试这样做updatepatch将其输入,apiVersion: apps/v1您将收到field is immutable错误消息。改变的唯一方法labels/selectors是重新部署整个Deployment.

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

请记住,您也可以使用更多patching methodslikeJSON merge patchmerge patch using the retainKeys strategy

测试

基于文档部署示例

您无法更改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,可以像在这个 stackoverflow 线程中一样进行修补。

在文档中使用战略合并补丁更新部署,您可以找到 2 个示例,container其中patchStrategy:"merge"

补丁策略由 Kubernetes 源代码中字段标签中的 patchStrategy 键的值指定。例如,PodSpec 结构体的 Containers 字段有一个合并的 patchStrategy:

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

补丁容忍度.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,因为这些字段是不可变的。

当你想修补某些东西时,你必须检查哪个是 default patchStrategy

补丁策略由 Kubernetes 源代码中字段标签中的 patchStrategy 键的值指定。

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

您可以使用一些补丁方法:

换句话说,补丁中的列表与现有列表合并。

战略合并补丁不同于 JSON 合并补丁。使用 JSON 合并补丁,如果要更新列表,则必须指定整个新列表。并且新列表完全取代了现有列表。

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


推荐阅读