OpenShift is a family of containerization software products developed by Red Hat. Its flagship product is the OpenShift Container Platform — an on-premises platform as a service built around Linux containers orchestrated and managed by Kubernetes on a foundation of Red Hat Enterprise Linux.
In this article im trying to leverage one of Kubernetes feature, which is ConfigMap and create an Spring Boot app that can read a ConfigMap dynamically. Which means we can replace, refresh, and reload the content of ConfigMap anytime and application will read it without have to restart.
Basically we can see on this diagram below what is the approach,

First lets create a file with the name of application-ocp-dev.properties,
spring.application.name=hello-world spring.cloud.config.enabled=false management.endpoints.web.exposure.include=refresh name=edwin
and upload it into OpenShift as a ConfigMap,
$ oc create configmap ocp-dev-config --from-file=application-ocp-dev.properties
Next lets create a Spring Boot app. We can see that other than a regular Spring Boot libraries, i also add Spring Cloud libraries there as well.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edw</groupId>
<artifactId>spring-cloud-client</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.10</version>
<relativePath/>
</parent>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Now lets create 2 Java files to make this apps runs,
package com.edw;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package com.edw.controllers;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RefreshScope
@RestController
public class IndexController {
@Value("${name:Somewhat Default}")
private String message;
@GetMapping("/")
public String getMessage() {
return this.message;
}
}
Lets deploy our Java app to Openshift using RHEL 8 with OpenJDK 11 as its based image
$ oc new-build . --name=spring-cloud-client -i openshift/openjdk-11-rhel8:1.0 $ oc start-build spring-cloud-client --from-dir=. --follow --wait $ oc new-app spring-cloud-client
We can see that apps would deployed to OpenShift but perhaps cannot start at all due to missing configuration. This is where we can leverage OpenShift ConfigMap, we can start with mounting ConfigMap into the apps where we mount it into /tmp/configs folder.
$ oc set volume dc/spring-cloud-client --add \ --name=app-config-mnt --configmap-name=ocp-dev-config \ --mount-path=/tmp/configs
And set our apps configuration so that it would point to the new ConfigMap by setting SPRING_CONFIG_LOCATION environment variables.
$ oc set env dc/spring-cloud-client \ SPRING_CONFIG_LOCATION=/tmp/configs/application-ocp-dev.properties
We can see that application now able to read value from our application configuration which resides on ConfigMap.
$ curl -k https://spring-cloud-client.openshift.com/ edwin
Lets try to replace the content of our properties file,

Save it and wait for one-two minutes in order for Kubelet and ConfirMaps to sync. AFter that we can refresh our apps’s configuration by running a CURL command to this URL
curl -kv -L -X POST 'https://spring-cloud-client.openshift.com/actuator/refresh'
And see the result from CURL,
$ curl -k https://spring-cloud-client.openshift.com/ my other name
And all the code on this article can be accessed here,
https://github.com/edwin/dynamic-spring-boot-configuration-on-openshift-4
Have fun with Spring Boot.
ps. if we think that syncing ConfigMap into mounted Pods took too long (around 2mins), we can accelerate them by annotate the Pods where ConfigMaps are mounted to.
$ oc annotate pod -l app=spring-cloud-client random-annotate-value="put some random string here" --overwrite