<p>I am trying to program the patching/rolling upgrade of k8s apps by taking deployment snippets as input. I use <code>patch()</code> method to apply the snippet onto an existing deployment as part of rollingupdate using <a href="https://github.com/fabric8io/kubernetes-client" rel="nofollow noreferrer">fabric8io's k8s client APIS</a>.. Fabric8.io <code>kubernetes-client</code> version <code>4.10.1</code>
I'm also using some loadYaml helper methods from <code>kubernetes-api 3.0.12.</code></p>

<p>Here is my sample snippet - adminpatch.yaml file:</p>

<pre><code>    kind: Deployment   
    spec:
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 0     
      template:
        spec:
          containers:
            - name: ${PATCH_IMAGE_NAME}
              image: ${PATCH_IMAGE_URL}
              imagePullPolicy: Always
</code></pre>

<p>I'm sending the above file content (with all the placeholders replaced) to patchDeployment() method as string. 
Here is my call to fabric8 patch() method:</p>

<pre><code>     public static String patchDeployment(String deploymentName, String namespace, String deploymentYaml) {
    try {
    Deployment deploymentSnippet = (Deployment) getK8sObject(deploymentYaml);
    if(deploymentSnippet instanceof Deployment) {
            logger.debug("Valid deployment object.");
    Deployment deployment = getK8sClient().apps().deployments().inNamespace(namespace).withName(deploymentName)
        .rolling().patch(deploymentSnippet);
    System.out.println(deployment.toString());
    return getLastConfig(deployment.getMetadata(), deployment);
    }
    } catch (Exception Ex) {
      Ex.printStackTrace();
    }
      return "Failed";
  }

</code></pre>

<p>It throws the below exception: </p>

<pre><code>&gt; io.fabric8.kubernetes.client.KubernetesClientException: Failure
&gt; executing: PATCH at:
&gt; https://10.44.4.126:6443/apis/apps/v1/namespaces/default/deployments/patch-demo.
&gt; Message: Deployment.apps "patch-demo" is invalid: spec.selector:
&gt; Invalid value:
&gt; v1.LabelSelector{MatchLabels:map[string]string{"app":"nginx",
&gt; "deployment":"3470574ffdbd6e88d426a77dd951ed45"},
&gt; MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is
&gt; immutable. Received status: Status(apiVersion=v1, code=422,
&gt; details=StatusDetails(causes=[StatusCause(field=spec.selector,
&gt; message=Invalid value:
&gt; v1.LabelSelector{MatchLabels:map[string]string{"app":"nginx",
&gt; "deployment":"3470574ffdbd6e88d426a77dd951ed45"},
&gt; MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is
&gt; immutable, reason=FieldValueInvalid, additionalProperties={})],
&gt; group=apps, kind=Deployment, name=patch-demo, retryAfterSeconds=null,
&gt; uid=null, additionalProperties={}), kind=Status,
&gt; message=Deployment.apps "patch-demo" is invalid: spec.selector:
&gt; Invalid value:
&gt; v1.LabelSelector{MatchLabels:map[string]string{"app":"nginx",
&gt; "deployment":"3470574ffdbd6e88d426a77dd951ed45"},
&gt; MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is
&gt; immutable, metadata=ListMeta(_continue=null, remainingItemCount=null,
&gt; resourceVersion=null, selfLink=null, additionalProperties={}),
&gt; reason=Invalid, status=Failure, additionalProperties={}).

</code></pre>

<p>I also tried the original snippet(with labels and selectors) with <code>kubectl patch deployment &lt;DEPLOYMENT_NAME&gt;  -n &lt;MY_NAMESPACE&gt; --patch "$(cat adminpatch.yaml)</code> and this applies the same snippet fine. </p>

<p>I could not get much documentation on fabric8io k8s client patch() java API. Any help will be appreciated.  </p>

<p>With latest improvements in Fabric8 Kubernetes Client, you can do it both via <code>patch()</code> and <code>rolling()</code> API apart from using <code>createOrReplace()</code> which is mentioned in older answer.</p>
<h2>Patching JSON/Yaml String using <code>patch()</code> call:</h2>
<p>As per latest release v5.4.0, Fabric8 Kubernetes Client does support patch via raw string. It can be either YAML or JSON, see <a href="https://github.com/fabric8io/kubernetes-client/blob/master/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/PatchTest.java#L107" rel="nofollow noreferrer">PatchTest.java</a>. Here is an example using raw JSON string to update image of a Deployment:</p>
<pre class="lang-java prettyprint-override"><code>try (KubernetesClient kubernetesClient = new DefaultKubernetesClient()) {
  kubernetesClient.apps().deployments()
    .inNamespace(deployment.getMetadata().getNamespace())
    .withName(deployment.getMetadata().getName())
    .patch(&quot;{\&quot;spec\&quot;:{\&quot;template\&quot;:{\&quot;spec\&quot;:{\&quot;containers\&quot;:[{\&quot;name\&quot;:\&quot;patch-demo-ctr-2\&quot;,\&quot;image\&quot;:\&quot;redis\&quot;}]}}}}&quot;);
}
</code></pre>
<h2>Rolling Update to change container image:</h2>
<p>However, if you just want to do rolling update; You might want to use <code>rolling()</code> API instead. Here is how it would look like for updating image of an existing Deployment:</p>
<pre class="lang-java prettyprint-override"><code>try (KubernetesClient client = new DefaultKubernetesClient()) {
    // ... Create Deployment 

    // Update Deployment for a single container Deployment
    client.apps().deployments()
            .inNamespace(namespace)
            .withName(deployment.getMetadata().getName())
            .rolling()
            .updateImage(&quot;gcr.io/google-samples/hello-app:2.0&quot;);
}
</code></pre>
<h2>Rolling Update to change multiple images in multi-container Deployment:</h2>
<p>If you want to update Deployment with multiple containers. You would need to use <code>updateImage(Map&lt;String, String&gt;)</code> method instead. Here is an example of it's usage:</p>
<pre class="lang-java prettyprint-override"><code>try (KubernetesClient client = new DefaultKubernetesClient()) {
    Map&lt;String, String&gt; containerToImageMap = new HashMap&lt;&gt;();
    containerToImageMap.put(&quot;nginx&quot;, &quot;stable-perl&quot;);
    containerToImageMap.put(&quot;hello&quot;, &quot;hello-world:linux&quot;);
    client.apps().deployments()
            .inNamespace(namespace)
            .withName(&quot;multi-container-deploy&quot;)
            .rolling()
            .updateImage(containerToImageMap);
}
</code></pre>
<h2>Rolling Update Restart an existing Deployment</h2>
<p>If you need to restart your existing Deployment you can just use the <code>rolling().restart()</code> DSL method like this:</p>
<pre class="lang-java prettyprint-override"><code>try (KubernetesClient client = new DefaultKubernetesClient()) {
    client.apps().deployments()
            .inNamespace(namespace)
            .withName(deployment.getMetadata().getName())
            .rolling()
            .restart();
}
</code></pre>
