Kubernetes ConfigMap Configuration and Reload Strategy
This story focuses on ConfigMap resource and its usage in pods over Kubernetes container and reload strategy in application real-time.
Please go through my earlier story for Minikube installation and deploying the sample application in Kubernetes runtime in Minikube.
Why ConfigMap?
Many applications require configuration via some combination of config files, command line arguments, and environment variables. These configuration artifacts should be decoupled from image content in order to keep containerized applications portable. The ConfigMap API resource provides mechanisms to inject containers with configuration data while keeping containers agnostic of Kubernetes. ConfigMap can be used to store fine-grained information like individual properties or coarse-grained information like entire config files or JSON blobs.
This seperates the tight coupling between application and configuration properties under same package. The ConfigMap residing at container and available for the application at runtime when deployed in pod.
Overview of ConfigMap
The ConfigMap API resource holds key-value pairs of configuration data that can be consumed in pods or used to store configuration data for system components such as controllers. ConfigMap is similar to Secrets, but designed to more conveniently support working with strings that do not contain sensitive information.
Note: ConfigMaps are not intended to act as a replacement for a properties file. ConfigMaps are intended to act as a reference to multiple properties files. You can think of them as way to represent something similar to the /etc directory, and the files within, on a Linux computer.
Example of ConfigMap
- kind:- The kind is ConfigMap
- metadata:- It holds the improtant information line ConfigMap name, namespace and others. This data is mapped in Pod or deployment config.
- data:- This field contains the configuration data. As you can see, ConfigMaps can be used to hold fine-grained information like individual properties or coarse-grained information like the contents of configuration files.
Create ConfigMap:
ConfigMaps can be created from directories, files and literal values. Here we will apply config in our sample applcation.
Sample Spring Boot application to load config properties from ConfigMap
- Maven dependencies :- Spring Boot latest version is used.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-config</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
- bootstrap.yml :- In spring cloud applications, few of the config properties should be known to kubernetes runtime before deployment actually starts.
spring:
cloud:
kubernetes:
config:
enabled: true
sources:
- namespace: default
name: minikube-sample
management:
endpoint:
restart:
enabled: true
sources :- name is minikube-sample which is configmap mapping.
- RestController:- properties are loaded in application for @ConfigurationProperties.
@RestController
@RequestMapping("/home")
public class HomeResource {
@Autowired
PropertiesConfig config;
@GetMapping("/data")
public ResponseEntity<ResponseData> getData() {
ResponseData responseData = new ResponseData();
responseData.setId(1);
responseData.setName(config.getName());
responseData.setPlace("Hyderabad");
responseData.setValue(config.getTest());
return new ResponseEntity<>(responseData, HttpStatus.OK);
}
@Getter
@Setter
public class ResponseData {
private String name;
private Integer id;
private String place;
private String value;
}
}
The name and value are set from config properties.
- deployment.yaml :- Service kind as NodePort dedicated to a port number. ConfigMaps are mappedn through volume mounts. The Service and deployments binds to application from metadata : name.
- ConfigMaps are maped to this pod from volumes and volumeMounts. ie., by name. Here in this example the value is “config”.
kind: Service
apiVersion: v1
metadata:
name: minikube-sample
spec:
selector:
app: minikube-sample
ports:
- protocol: TCP
port: 8080
nodePort: 30083
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: minikube-sample
namespace: default
spec:
selector:
matchLabels:
app: minikube-sample
replicas: 1
template:
metadata:
labels:
app: minikube-sample
spec:
containers:
- name: minikube-sample
image: minikube-sample:latest
imagePullPolicy: Never
ports:
- containerPort: 8080
env:
- name: env.namespace
value: default
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
configMap:
name: minikube-sample
Deploy the application in to Kubernetes. Please see the steps from console
Now go to browser and test Rest API endpoint
The name and value above is picked from ConfigMap.
ConfigMap Reload Feature
Some applications may need to detect changes on external property sources and update their internal status to reflect the new configuration. The reload feature of Spring Cloud Kubernetes is able to trigger an application reload when a related ConfigMap
or Secret
changes.
This feature is disabled by default and can be enabled using the configuration property spring.cloud.kubernetes.reload.enabled=true
(eg. in the application.properties/yml file).
The following levels of reload are supported (property spring.cloud.kubernetes.reload.strategy
): - refresh
(default): only configuration beans annotated with @ConfigurationProperties
or @RefreshScope
are reloaded. This reload level leverages the refresh feature of Spring Cloud Context. - restart_context
: the whole Spring ApplicationContext is gracefully restarted. Beans are recreated with the new configuration. - shutdown
: the Spring ApplicationContext is shut down to activate a restart of the container. When using this level, make sure that the lifecycle of all non-daemon threads is bound to the ApplicationContext and that a replication controller or replica set is configured to restart the pod.
For more details please visit here.
Now Let’s rework on same sample spring-boot application to make reloadable at run time without restarting the application.
To make it work we have to add restart enable and other configurations in bootstrap.yml
Lets rebuild the application with earlier steps like clean build and create docker image (For some reasons docker of windows version is not working properly in my laptop. So I am using minikube docker.)
Lets test Rest API Endpoint
Lets change configMap property values while the application is in running state.
Lets pull the logs
Observe the lines from highlighted to the end of it. When we changes the configMap manually, Kubernetes detected the change and reloaded the spring context gracefully.
Let’s hit again the Rest API endpoint. You will see the updated values.
Important things to keep in mind:
The view
role on the service account is required in order to listen for config map changes.
kubectl create clusterrolebinding <view-name> --clusterrole=view --serviceaccount=<namespace>:default --namespace=<namespace>
The following levels of reload are supported (property spring.cloud.kubernetes.reload.strategy
): - refresh
(default): only configuration beans annotated with @ConfigurationProperties
or @RefreshScope
are reloaded. This reload level leverages the refresh feature of Spring Cloud Context. - restart_context
: the whole Spring ApplicationContext is gracefully restarted. Beans are recreated with the new configuration. - shutdown
: the Spring ApplicationContext is shut down to activate a restart of the container. When using this level, make sure that the lifecycle of all non-daemon threads is bound to the ApplicationContext and that a replication controller or replica set is configured to restart the pod.
Please find source code here
References :