By leveraging the official Kubernetes client libraries for C#, we can easily interact with any Kubernetes cluster. We can also update (or patch) existing objects by invoking the corresponding Patch*
methods (like PatchNamespacedPod
, PatchNamespacedConfigMap
, and many more) provided by the client library.
Although we can construct patches from different formats (JsonPatch
, ApplyPatch
, MergePatch
, or StrategicMergePatch
), we’ll focus on JsonPatch
for the sake of this article, and we will update the following ConfigMap:
#configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: sample
namespace: default
data:
firstName: Bob
You can quickly create the ConfigMap shown above using either kubectl create configmap sample -n default --from-literal firstName=Bob
or by saving the yaml
to a local file and use kubectl apply -f configmap.yml
.
Patching a Config Map - The regular way
Let’s first take a look at how we can patch the ConfigMap by leveraging the default Kubernetes
client libraries for C#:
using k8s;
using k8s.Models;
var cfg = KubernetesClientConfiguration.BuildDefaultConfig();
var client = new Kubernetes(cfg);
var configMap = "sample";
var @namespace = "default";
var jsonPatch = @"
[
{
""path"": ""/data/name"",
""op"": ""replace"",
""value"": ""John""
}
]";
var patch = new V1Patch(jsonPatch, V1Patch.PatchType.JsonPatch);
client.PatchNamespacedConfigMap(patch, configMap, @namespace);
As you can see, the patch instructions resist as simple string
here. Obviously, storing the instructions about what to modify as a magical string is a smell and may have a negative impact on the overall maintainability of the code.
Patching a Config Map - Using Microsoft.AspNetCore.JsonPatch
Alternatively, we can use Microsoft.AspNetCore.JsonPatch
(available on NuGet), to get rid of the magic string
(jsonPatch
). However, this requires some plumbing which blows up the entire sample:
using System.Text.Json;
using k8s;
using k8s.Models;
using Microsoft.AspNetCore.JsonPatch;
using Newtonsoft.Json.Serialization;
var cfg = KubernetesClientConfiguration.BuildDefaultConfig();
var client = new Kubernetes(cfg);
var configMap = "sample";
var @namespace = "default";
var doc = new JsonPatchDocument<V1ConfigMap>();
doc.ContractResolver = new DefaultContractResolver {
NamingStrategy = new CamelCaseNamingStrategy()
};
doc.Replace(c => c.Data["name"], "John");
var jsonPatch = JsonSerializer.Serialize(
doc.Operations.Select(o=> new {
o.path,
o.op,
o.value
})
);
var patch = new V1Patch(jsonPatch, V1Patch.PatchType.JsonPatch);
client.PatchNamespacedConfigMap(patch, configMap, @namespace);
By using Microsoft.AspNetCore.JsonPatch
, we could remove the magic string 🙌🏼. However, creating a RFC compliant JSON Patch expression requires a bunch of plumbing. We’ve to configure the ContractResolver
for our instance of JsonPatchDocument
and we’ve to ensure that spec compliant JSON patch is being generated.
Patching a ConfigMap - The simple way
I’ve published a small NuGet package (ThorstenHans.JsonPatch.Contrib), which will take care of all the plumbing. You can add the NuGet package to the .NET project using dotnet add package ThorstenHans.JsonPatch.Contrib
. Once the NuGet package is installed, we’ve access to JsonPatchDocumentBuilder.BuildFor<T>
and we can use the ToJsonPatch()
method on JsonPatchDocument<T>
.
JsonPatchDocumentBuilder.BuildFor<T>
constructs a new instance of JsonPatchDocument<T>
and configures the ContractResolver
correctly. We can use ToJsonPatch()
to receive a valid Json patch expression as string
.
Using those methods makes the entire sample easier to read and requires less code:
using k8s;
using k8s.Models;
using ThorstenHans.JsonPatch.Contrib;
var cfg = KubernetesClientConfiguration.BuildDefaultConfig();
var client = new Kubernetes(cfg);
var configMap = "sample";
var @namespace = "default";
var doc = JsonPatchDocumentBuilder.BuildFor<V1ConfigMap>();
doc.Replace(c => c.Data["name"], "John");
var jsonPatch = doc.ToJsonPatch();
var patch = new V1Patch(jsonPatch, V1Patch.PatchType.JsonPatch);
client.PatchNamespacedConfigMap(patch, configMap, @namespace);
Conclusion
Kubernetes client SDK for C# offers different ways for updating existing objects in a Kubernetes cluster. When relying on JsonPatch
, the small NuGet package demonstrated here can simplify your codebase, and you could get rid of some plumbing.