Patching Kubernetes Resources from Java with Fabric8 Kubernetes Client 7
Introduction
When managing Kubernetes resources programmatically, you might need to update parts of an existing resource without replacing it entirely. Kubernetes controllers and operators often use patching to update resources in a more efficient and controlled way. With the Fabric8 Kubernetes Client 7, there are several patching strategies available that map directly to Kubernetes native patch mechanisms.
In this post, I'll show you the three main patch methods: Strategic Merge Patch, JSON Patch, and JSON Merge Patch, and code examples for each.
What are the different patch methods in Kubernetes?
Kubernetes provides three main patch methods to update resources:
Strategic Merge Patch
The Strategic Merge Patch is a Kubernetes-specific patch format that allows you to update specific fields in a resource. This patch method is designed to be more user-friendly and less error-prone than other patch formats. It's particularly useful for updating resources that have a well-defined schema, such as Custom Resource Definitions (CRDs).
JSON Patch (RFC 6902)
JSON Patch is a standard format defined in RFC 6902 that describes how to apply a list of operations to a JSON document. Each operation specifies a change to be applied to the target document.
The following snippet shows an HTTP transaction that applies a JSON Patch to an HTTP resource:
PATCH /api/data/my-resource HTTP/1.1
Host: example.com
Content-Length: 152
Content-Type: application/json-patch+json
[
{ "op": "add", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "replace", "path": "/a/b/c", "value": "bar" }
]
JSON Merge Patch (RFC 7396)
JSON Merge Patch is a simpler patch format that works like a "partial update" of a JSON document as defined in RFC 7396.
You supply a JSON document with the fields to change.
Setting a field to null
can remove it.
The Fabric8 Kubernetes Client provides support for all these patch types, making it a versatile tool for Java developers working with Kubernetes and OpenShift.
Patching resources with Fabric8 Kubernetes Client 7
The Fabric8 Kubernetes Client 7 provides a straightforward way to patch resources using the three main patch methods in Kubernetes.
Strategic Merge Patch
By default, Fabric8 provides a simple method that accepts a raw JSON (or YAML) string for a strategic merge patch. For example, suppose you want to update the container image of a Deployment. You can write:
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
public class StrategicMergePatch {
public static void main(String[] args) {
try (KubernetesClient client = new KubernetesClientBuilder().build()) {
String patch = "{"
+ " \"spec\": {"
+ " \"template\": {"
+ " \"spec\": {"
+ " \"containers\": ["
+ " {\"name\": \"my-container\", \"image\": \"nginx:latest\"}"
+ " ]"
+ " }"
+ " }"
+ " }"
+ "}";
client.apps().deployments().inNamespace("default").withName("my-deployment")
.patch(patch);
}
}
}
In this snippet the patch string updates the container's image in a Deployment.
Because we use the plain patch(String)
method, Fabric8 uses the strategic merge patch algorithm by default.
JSON Patch
If you require more granular control, for example, when you need to replace a field value using a precise path, you can use JSON Patch.
With Fabric8, this is achieved by specifying a PatchContext
with the patch type set to JSON
.
Consider the following example that updates a container image:
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
import io.fabric8.kubernetes.client.dsl.base.PatchType;
public class JsonPatch {
public static void main(String[] args) {
try (KubernetesClient client = new KubernetesClientBuilder().build()) {
String patch = "["
+ "{\"op\": \"replace\", \"path\": \"/spec/template/spec/containers/0/image\", \"value\": \"nginx:latest\"}"
+ "]";
client.apps().deployments().inNamespace("default").withName("my-deployment")
.patch(PatchContext.of(PatchType.JSON), patch);
}
}
}
The previous snippet illustrates a few key points:
- The Fabric8 client provides a
patch(PatchContext, String)
method that accepts aPatchContext
object and a JSON Patch string. - The
PatchContext
object specifies the patch type asJSON
. PatchContext.of(PatchType)
is a convenient way to create aPatchContext
object with the desired patch type.- Additionally, you can set options such as
force
,fieldManager
, andfieldValidation
in thePatchContext
by using thePatchContext.Builder
. - The JSON Patch string contains the operation to replace the container image in the Deployment as specified by RFC 6902.
JSON Merge Patch
For a simpler patch operation, you can use the JSON Merge Patch method. It is useful when you simply want to update or remove fields in a resource.
The following example demonstrates how to remove an annotation from a resource:
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
import io.fabric8.kubernetes.client.dsl.base.PatchType;
public class JsonMergePatch {
public static void main(String[] args) {
try (KubernetesClient client = new KubernetesClientBuilder().build()) {
// In this patch, setting the "foo" annotation to null removes it.
String jsonMergePatch = "{"
+ "\"metadata\": {"
+ " \"annotations\": {"
+ " \"foo\": null"
+ " }"
+ "}"
+ "}";
PatchContext patchContext = PatchContext.of(PatchType.JSON_MERGE);
client.apps().deployments().inNamespace("default").withName("my-deployment")
.patch(patchContext, jsonMergePatch);
}
}
}
In this example, the JSON Merge Patch string removes the foo
annotation from the resource by setting it to null
.
When to use each patch method
Each patch method has its own use cases and benefits:
- Strategic Merge Patch: Use this method when you want to update specific fields in a standard Kubernetes resource. It intelligently merges lists and maps, without affecting other fields.
- JSON Patch: Ideal for fine-grained operations when you need precise control over what to add, remove, or replace. It works well when you're comfortable specifying JSON pointer paths.
- JSON Merge Patch: A simpler method for partial updates. It's useful when you want to update or remove fields without specifying the exact path.
Note
Remember that patching has some pitfalls. For example, updating immutable fields (such as certain selectors) will result in errors.
Always consult the Kubernetes API documentation and test your patch operations thoroughly.
Conclusion
Patching Kubernetes resources using the Fabric8 Kubernetes Client version 7 is a powerful way to manage updates programmatically. By leveraging Strategic Merge Patch, JSON Merge Patch, and JSON Patch, you can handle a variety of use cases with ease. Whether adding annotations, updating container images, or modifying configurations, Fabric8 provides a robust API for interacting with your cluster.
You can find the complete source code for this post on GitHub.
Happy patching!