Dhananjay.blog

Recipes for Java, Golang on Kubernetes and more.

Menu
  • Home
  • About
Menu

Go Service Configuration with k8s ConfigMaps

Posted on December 27, 2022

Go Service Configuration: Step by Step instructions to configure a Go Service to read from a ConfigMap and refresh automatically when it changes. This article is similar to an earlier post on Spring Boot Series.

This article uses the Kubernetes Go Client to call respective apis that reads the configuration from the K8s ConfigMap, and then create a watcher and subscribe for any updates to the ConfigMap.

Pre-Requisites

Follow the steps as listed in this post to create a Go Service that runs on K8s and is installed using Helm. Here is how your project folder structure should look like once done:

Go Service Configuration project.

1. Create Roles

Create appropriate roles and bind it the pod service account. This will be provide necessary permissions to the application for reading various k8s objects such as ConfigMap. Navigate to helm chart directory ms-template/templates create roles.yaml and rolebinding.yaml with the following content

role.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: {{ include "ms-template.name" . }}
  labels:
    {{- include "ms-template.labels" . | nindent 4 }}
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources: ["pods","configmaps","endpoints","services"]
    verbs: ["get", "watch", "list"]

rolebinding.yaml : To attach the role created above with the pod service account.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: {{ include "ms-template.name" . }}
  labels:
    {{- include "ms-template.labels" . | nindent 4 }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: {{ include "ms-template.name" . }}
subjects:
  - kind: ServiceAccount
    name: {{ include "ms-template.name" . }}

2. Install Kubernetes Go Client

Run the following command in the root directory of the project.

go get k8s.io/client-go@latest

3. Create ConfigMap Instance

We will use these to store instances of configmap and k8s clientset

var (
	configmap     *v12.ConfigMap
	configMapName = "ms-template"
	clientset     *kubernetes.Clientset
)

Create an instance of confirmap when your service starts

func main() {
	initialize()
	r := gin.Default()
	r.GET("/health", healthCheck)
	r.GET("/configmap", printConfigmap)
	r.Run("0.0.0.0:8080")
	log.SetOutput(os.Stdout)
}

func initialize() {
	// initialize client
	config, _ := rest.InClusterConfig()
	var configErr error
	clientset, configErr = kubernetes.NewForConfig(config)
	if configErr != nil {
		panic(configErr.Error())
	}

	configmaps := clientset.CoreV1().ConfigMaps("default")
	initializeConfigmap(&configmaps)
}

func initializeConfigmap(configmaps *v13.ConfigMapInterface) {
	var err error
	cfgs := *configmaps
	configmap, err = cfgs.Get(context.TODO(), configMapName, v1.GetOptions{})
	if err != nil {
		fmt.Printf("Unable to retreive %v, errror:%v", configMapName, err)
		panic(err.Error())
	}
	fmt.Printf("\nCreated/Refreshed Configmap Object Value from k8s configmap %v", configMapName)
}

This will create a global configmap instance that can be used by the application. Next up lets complete the Go Service configuration by subscribing to change events from a ConfigMap.

4. Create Watcher and Subscribe

Add the following method in main.go file

func startConfigMapWatch(configmaps *v13.ConfigMapInterface) {
	cfgs := *configmaps
	watcher, err := cfgs.Watch(context.TODO(), v1.ListOptions{})
	if err != nil {
		fmt.Printf("Unable to Create a watcher on configmap %v, with errror:%v", configMapName, err)
		panic(err.Error())
	}

	for event := range watcher.ResultChan() {
		cfg := event.Object.(*v12.ConfigMap)
		switch event.Type {
		case watch.Modified:
			if strings.Contains(cfg.ObjectMeta.Name, configMapName) {
				fmt.Printf("\nConfigmap %s/%s modified", cfg.ObjectMeta.Namespace, cfg.ObjectMeta.Name)
				initializeConfigmap(configmaps)
			}
		}
	}
}

The above code creates a watcher and subscribes to any change events the configmap. On receiving a change event it will replace the existing copy of the configmaps var with the latest one. Then finally in the initializeconfigmap method add the following lines to call the above method in a separate go subroutine go startConfigMapWatch(&configmaps)

5. Create Test Endpoint for Go Service Configuration

Create a test api to print the ConfigMap object values , this will help us verify whether our go service is able to read from the ConfigMap. Add the following to the main.go.

func main() {
.....
	r.GET("/configmap", printConfigmap)
.....
}

func printConfigmap(c *gin.Context) {
	c.JSON(http.StatusOK, configmap.Data)
}

The code above will create an endpoint /configmap that will print the values within the data block of the configmap.

Here is how main.go file should look like once done.

6. Build Image and Deploy

Build the image with the code above and add the tag to the helm chart chart.yaml file

docker build -t ms-template:0.2 . && helm install ms-template ms-template/

and then install via helm charts, ensure that chart.yaml has the above 0.2 tag before doing so

helm install ms-template ms-template/

7. Testing Go Service Configuration

Lets test the changes, first up lets verify whether our code was able to read the Configmap

$ curl http://localhost:8080/configmap
{"app.properties":"scale=1\nchances=2\n"}

$ kubectl edit configmap ms-template
configmap/ms-template edited

$ curl http://localhost:8080/configmap
{"app.properties":"scale=1001\nchances=2\n"}

In the logs you will see the following, which verifies the modified event was received by our go program

[GIN] 2022/12/27 - 18:00:13 | 200 |      353.96µs |    192.168.65.3 | GET      "/configmap"
Configmap default/ms-template modified
Created/Refreshed Configmap Object Value from k8s configmap ms-template[GIN] 2022/12/27 - 18:00:50 | 200 |      54.026µs |        10.1.0.1 | GET      "/health"
[GIN] 2022/12/27 - 18:00:57 | 200 |      36.642µs |    192.168.65.3 | GET      "/configmap"

Troubleshooting

Troubleshooting any failure or issues is similar to how you would do it for other Kubernetes workloads. Here are some tips on easy starting over

  1. If something goes wrong in helm and you want to start over just delete the chart by running helm delete ms-template
  2. YAML is very sensitive to indentation, so please ensure that the indentation is proper. 
  3. if all else fails you can still download the code from the GitHub repo and try comparing it with your setup

The entire source code for this post is available here. 

Further Reading 

  • Kubernetes Go Client

Categories

  • GO
  • Home
  • Java
  • K8s and More
  • Programming
  • Software

Tags

Container Image Docker gingonic go helm jib kafka kubernetes microservices springboot spring cloud config tdd test driven development unit testing

Recent Posts

  • Unit Testing Checklist
  • ConfigMap Custom Watcher with SpringBoot
  • Go Service Configuration with k8s ConfigMaps
  • Go MicroService in Gin using Helm On k8s
  • Container Image Reducing Size with Jib

Archives

  • March 2025
  • January 2023
  • December 2022
  • September 2022
  • August 2022

Categories

  • GO
  • Home
  • Java
  • K8s and More
  • Programming
  • Software

About

  • Privacy
  • Terms of Service
  • About
  • Contact
@2024 Dhananajay on Tech