Kubernetes ConfigMap integration with spring boot application

Kubernetes ConfigMap integration with spring boot application

In the last Kubernetes article, we have created a simple spring boot application, its Docker image, and deployed it in the Kubernetes cluster. Refer same if you are new to Kubernetes, want to do development setup, and create a simple application in Kubernetes. In this article, we'll extend our basic application to integrate with the Kubernetes ConfigMap.

Every application requires some environment-specific attributes which we can not hard-code in our application. There are different ways to solve this problem in the spring boot application like passing it as JVM argument while starting the application or creating an application configuration file based on the environment, and passing it as a reference while starting the application.

We can not use a direct file as a configuration file in Kubernetes, instead, we have ConfigMap to solve configuration problems in Kuberntes. With the help of the ConfigMap, we can configure or specify environment-specific attributes in different ways. Today in this article we are going to explore different ways to use ConfigMap and configure the environment-specific attributes with the help of a spring boot application.

In this article, I have added a core code snippet and a few commands. For detailed reference refer GITHUB REPO

Prerequisites

  1. JDK
  2. Maven
  3. Docker
  4. Minikube or Kubernetes cluster
  5. Basic knowledge of Java, Spring boot, docker, and Kubernetes

Different ways to use ConfigMap with container

  1. Container command and JVM Argument
  2. Environment variable
  3. File

As part of this article, we will use the spring boot application which sources three runtime attributes from a configuration file and environment variables.

Follow the below steps to create and deploy a sample application to the Kubernetes cluster.

1. Create UserDetailsController as below. This file contains three attributes generally we read it from application properties or YAML files but here we are going to read it from ConfigMap and JVM arguments.
@RestController
public class UserDetailsController {

    @Value("${user.firstName:default}")
    private String firstName;

    @Value("${user.lastName:default}")
    private String lastName;

    @Value("${user.age:0}")
    private Integer age;

    @RequestMapping(value = "user-details", method= RequestMethod.GET)
    public String getFirstName() {
        return "user-details {" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", age=" + age +
                '}';
    }

}
2. Create a ConfigMap file as below. All the attributes in ConfigMap should be part of the data section. We can specify attributes as normal attributes or within the file as well. Here as part of this demo, firstName is a normal attribute and lastName is an attribute within the file.
apiVersion: v1
kind: ConfigMap
metadata:
  name: hello-world-cm
data:
  user.firstName: "Yogesh"
  user-details.properties: |
    user.lastName=Patel
3. Create a ConfigMap from the below command.
kubectl apply -f config-map.yaml
4. Describe ConfigMap from the below command. It will display all the attributes defined in ConfigMap. As shown in the below image ConfigMap has been created with key-value pair.
kubectl describe cm hello-world-cm

cm-details.png

5. Create a pod that reads different parameters from ConfigMap or JVM args. The way we define attributes in ConfigMap we need to change our consumption method in a pod as well. There is not any similar way we can read attributes. It changes the way we define in ConfigMap. Below are a few key attributes that we have declared in ConfigMap and will configure in a pod.
  • user.age - It's normal attributes that we are passing it as an environment variable and we haven't specified it within the ConfigMap. We can directly use it as a name, and value pair within the env section.

  • user.firstName - It's an environment variable but we are sourcing it from ConfigMap. As we are sourcing it from ConfigMap we need to specify ConfigMap and attribute name as configMapKeyRef.

  • user.lastName - It's an attribute defined within the file in ConfigMap. As we can not link files directly to the pod we have to use Volume mount to access the same. As shown below to access the file we have to define Volumes and VolumeMount.

  • JAVA_TOOL_OPTIONS - Spring boot application requires a path from where to read the configuration file, in our case file is mounted to /config/user-details.properties path so we have to provide full path for the same. It's again an environment variable that will be used while starting the pod.

apiVersion: v1
kind: Pod
metadata:
  name: hello-world
  labels:
    name: hello-world
spec:
  containers:
    - name: hello-world
      image: hello-world:1.0.1
      env:
        - name: user.age
          value: "30"
        - name:- USER.FIRSTNAME
          valueFrom:
            configMapKeyRef:
              name: hello-world-cm
              key: user.firstName
        - name: JAVA_TOOL_OPTIONS
          value: -Dspring.config.location=/config/user-details.properties
      volumeMounts:
        - name: config
          mountPath: "/config"
          readOnly: true
  volumes:
    - name: config
      configMap:
        name: hello-world-cm
        items:
          - key: "user-details.properties"
            path: "user-details.properties"
6. Refer last article to create a docker image, create a pod, expose service, troubleshoot with help of log, and test outside the Kubernetes container.