When we write resource manifest files with Kubernetes, we often use tools like Helm
or Kustomize
for templating, both to improve the flexibility of resource manifests and to really lower the threshold for installing complex Kubernetes applications. In this article we try to implement a YAML resource manifest file templating solution ourselves using Golang.
Golang’s Templating
Golang has a standard library text/template
that supports templated text files. This library allows us to run functions, assignments, and other operations, and can perform some logic to replace some of the template values in the source text, either by reading the text from the file or by parsing it from a string. Since we want to templatize the YAML file, we will read from the file, so we can use the code shown below to do this.
|
|
The above code reads a file located in filePath and uses it as a template, using the functions in availableFunctions
and the data in availableData
to populate all the template values. For example, we are reading a YAML file of ConfigMap.
Then we define availableData
and availableFunctions
as the code shown below.
The output of the above defined Read function call is shown below.
Using YAML in your application
When we use a CLI tool like kubectl, using YAML in Kubernetes is very simple:
|
|
However, if we were to write our own code to apply the YAML file, we would normally use the client-go
client toolkit, but client-go is for static types, and there is no corresponding information in the YAML file, but we can solve this problem with the following two options.
- Use Kind and Version in YAML to deserialize to static types, and then use its typed REST client to communicate.
- Using the Discovery feature, Discovery allows us to dynamically find the REST client of a given type instead of accessing it via static types, as we demonstrate below using this approach.
First we need to communicate with the APIServer as usual to create a ClientSet object. If we execute the code from a system that can use kubectl, this means that there is a kubeconfig
file available, which is usually the $HOME/.kube/config
file, as follows shown below.
|
|
The ClientSet acts as a gateway to communicate with the K8S cluster, using it we can fetch objects to give us the discovery interface. For the functionality we want to implement, we need to be able to query the type of a given resource and communicate with the REST client of that type, so we need a Discovery REST mapper and a Dynamic REST interface respectively, with the code shown below.
|
|
Next we look up the type of object represented in the YAML file and get a REST client that supports it so we can manipulate the resource object?
First call the previous Read function to read and execute a template.
In order to use our Discovery REST mapper and Dynamic REST interface, we need to decode the contents of the YAML file into a runtime.Objects
object.
The contents of the YAML file are first split according to --
(there may be multiple resource objects in a single YAML file).
The deserialization function of k8s.io is then used on each fragment to output the runtime.Object object and a structure holding the Group, Version and Kind information.
|
|
Now we can go back and use our RESTMapper to get a mapping with the GVK we got above.
With the resource type in place, we can use the previous dynamic REST interface to obtain the client of a specific resource object:
|
|
At this point we can use the resulting client objects in Kubernetes to perform operations such as creation and deletion!
|
|
At this point we’ve completed a lightweight YAML template processing tool using Golang.