<p>What does the MergePatch or StragegyMergePatch do when patching map type field like labels?</p>
<p>When I use MergePatch or StragegyMergePatch, if I add some labels in yaml file, then transfer the data of the entire yaml file to patch method, it could work. But if I remove some labels from yaml file, then patch, it doesn't work.</p>

shuiqiang
<p>I have investigate further and many things depends on what exactly you want to do on which <code>resource</code>. Documentation might be hard to understand so I will expand it more in this answer.</p>
<h3>Background</h3>
<p>You are referring to <a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-a-strategic-merge-patch-to-update-a-deployment" rel="nofollow noreferrer">Merge Patch</a> where you have example of merge patching (adding additional container) <code>spec.template.spec.containers</code>. Below you have <a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#notes-on-the-strategic-merge-patch" rel="nofollow noreferrer">Notes on the strategic merge patch</a>.</p>
<blockquote>
<p>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.</p>
</blockquote>
<blockquote>
<p>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.</p>
</blockquote>
<p>Default patch strategy can be found in <a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#-strong-api-overview-strong" rel="nofollow noreferrer">Kubernetes API documentation</a> or in the Kubernetes source code</p>
<p>Regarding patching <code>Deployments labels</code>, since <code>apiVersion: apps/v1</code> it's impossible. You can find confirmation in <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#label-selector-updates" rel="nofollow noreferrer">Deployments - Label selector updates</a>.</p>
<blockquote>
<p>Note: In API version apps/v1, a Deployment's label selector is immutable after it gets created.</p>
</blockquote>
<p>If you would try to <code>update</code> or <code>patch</code> it in <code>apiVersion: apps/v1</code> you will get an <code>field is immutable</code> error. Only way to change <code>labels/selectors</code> is to redeploy whole <code>Deployment</code>.</p>
<p>However, if you would use older Kubernetes version with <code>apiVersion: extensions/v1beta1</code> it could be patched like in <a href="https://gist.github.com/coresolve/364c80b817eb8d84bfb1c6e2c94d2886" rel="nofollow noreferrer">Github example</a>.</p>
<p><strong>Please keep in mind that you also can use more <code>patching methods</code></strong> like <code>JSON merge patch</code> or <code>merge patch using the retainKeys strategy</code>.</p>
<h3>Tests</h3>
<p>Based on <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment" rel="nofollow noreferrer">Documentation Deployment Example</a>.</p>
<p>You cannot change <code>Deployment</code> labels in <code>apiVersion: apps/v1</code>, thus you cannot <code>patch</code> it as well.</p>
<pre><code>$ kubectl apply -f nginx-second.yaml
The Deployment &quot;nginx-deployment&quot; is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{&quot;app&quot;:&quot;nginx&quot;, &quot;test&quot;:&quot;test&quot;}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable
</code></pre>
<p>In comments you referred to <code>Node Selector</code> which can be patched like in <a href="https://stackoverflow.com/questions/55357287/update-node-selector-field-for-pods-on-the-fly">this stackoverflow thread</a>.</p>
<p>In documentaton <a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-a-strategic-merge-patch-to-update-a-deployment" rel="nofollow noreferrer">Use a strategic merge patch to update a Deployment</a> you can find 2 examples, <code>container</code> which <code>patchStrategy:&quot;merge&quot;</code>:</p>
<blockquote>
<p>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:</p>
</blockquote>
<pre><code>type PodSpec struct {
  ...
  Containers []Container `json:&quot;containers&quot; patchStrategy:&quot;merge&quot; patchMergeKey:&quot;name&quot; ...`
</code></pre>
<p>and <code>tolerations</code> example which empty <code>patchStrategy</code> field.</p>
<blockquote>
<p>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.</p>
</blockquote>
<pre><code>type PodSpec struct {
  ...
  Tolerations []Toleration `json:&quot;tolerations,omitempty&quot; protobuf:&quot;bytes,22,opt,name=tolerations&quot;`
</code></pre>
<p>Both examples (with containers and tolerations) are list but difference is when you are using merge it's adding new ones, but when you want to replace, <code>key</code> value must be the same.</p>
<p><strong>patch-tolerations.yaml</strong></p>
<pre><code>$ cat patch-tolerations.yaml
spec:
  template:
    spec:
      tolerations:
      - effect: NoSchedule
        key: disktype
        value: ssd
        test1: testvalue1
        test2: testvalue2
        test3: testvalue3
</code></pre>
<p><strong>Replacing using the same keys</strong></p>
<pre><code>$ 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 &quot;$(cat patch-tolerations.yaml)&quot;

$ kubectl get deploy patch-demo -o yaml | grep tolerations: -A 5
      tolerations:
      - effect: NoSchedule
        key: disktype
        value: ssd
</code></pre>
<p>It replaced only values with the same <code>key</code>. If you would change <code>patch-tolerations.yaml</code> to</p>
<pre><code>spec:
  template:
    spec:
      tolerations:
      - effect: NoSchedule
        test1: testvalue1
        test2: testvalue2
        test3: testvalue3
</code></pre>
<p>You will get an error:</p>
<pre><code>$ kubectl patch deployment patch-demo --patch &quot;$(cat patch-tolerations.yaml)&quot;
The Deployment &quot;patch-demo&quot; is invalid: spec.template.spec.tolerations[0].operator: Invalid value: &quot;&quot;: operator must be Exists when `key` is empty, which means &quot;match all value
s and all keys&quot;
</code></pre>
<p><strong>Tests on StatefulSet</strong></p>
<p>As you asked about labels, you can change them in <code>statefulset</code>. Based on example from Docs <a href="https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#creating-a-statefulset" rel="nofollow noreferrer">Creating a StatefulSet</a> with some additional annotations <code>metadata.labels</code>.</p>
<pre><code>$ 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 &quot;$(cat patch-sts.yaml)&quot;
statefulset.apps/web patched
$ kubectl patch sts web --patch &quot;$(cat patch-sts-template.yaml)&quot;
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:
</code></pre>
<h3>Conclusion</h3>
<p>You are not able to change <code>Deployment labels</code> as those fields are immutable.</p>
<p>When you want to patch something, you have to check which is default <code>patchStrategy</code>.</p>
<blockquote>
<p>The patch strategy is specified by the value of the patchStrategy key in a field tag in the Kubernetes source code.</p>
</blockquote>
<p>In <code>merge</code> patch all informations are mixing, when using <code>replace</code> patch, new and old patching objects must have the same <code>key</code>.</p>
<p>You can use a few patch methods:</p>
<ul>
<li><a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-a-strategic-merge-patch-to-update-a-deployment" rel="nofollow noreferrer">Strategic merge patch</a></li>
</ul>
<blockquote>
<p>In other words, the list in the patch was merged with the existing list.</p>
</blockquote>
<ul>
<li><a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-a-json-merge-patch-to-update-a-deployment" rel="nofollow noreferrer">JSON merge patch</a></li>
</ul>
<blockquote>
<p>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.</p>
</blockquote>
<ul>
<li><a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-strategic-merge-patch-to-update-a-deployment-using-the-retainkeys-strategy" rel="nofollow noreferrer">Strategic merge patch using the retainKeys</a>.</li>
</ul>
<p><strong>If this didn't answer your question, please specify what you want to exactly achieve using which version, resource and what you want to patch.</strong></p>
