In Kubernetes, configmap is used for keeping properties for an application. Once Spring applications required restart just due to change in properties file to take effect. Now in cloud with the help of fabric8 Kubernetes client, restart is not required anymore. We can reflect changes in configuration to Spring Boot live without downtime.
There are two reload modes: polling and event. Polling as the name implies polls Kubernetes API periodically. Event is more effective since it takes effect when configmap changed. We will cover event mode reload in this post.
How events arrive Spring Boot? Does Kubernetes aware of our Spring Boot app? No. Don’t confuse this event with Kubernetes event.
Above you can see Websocket is used between Spring Boot and Kubernetes API Server. Assuming we are using namespace “default” in this example, changes to response in this address reflected to KubernetesClient https://{api_server_clusterip}/api/v1/namespaces/default/configmaps/k8s-live-reload-configmap . If kube-proxy does not allow WebSocket then API Server is polled by HttpClient.
In Spring side, bootstrap.yaml reload mode and configmap name given. I deliberately disabled actuator endpoints, because most examples include actuator endpoints, however it is not required because fabric8-client refreshes bean internally. In pom.xml however actuator dependencies needed since fabric8-config depends on actuator configuration classes. See example
spring:
application:
name: k8s-live-reload-example
cloud:
kubernetes:
reload:
enabled: true
mode: event
config:
sources:
- name: k8s-live-reload-configmap
management:
endpoints:
enabled-by-default: false #actuator endpoints disabled in order to show it is not required to reload config
Beans annotated with @ConfigurationProperties are refreshed.
@Configuration
@ConfigurationProperties(prefix = "bean" )
@Data
public class Config {
private String testvalue;
}
Run example
We need to build and push our application image to Docker and Kubernetes need to see this image. I suggest using Minikube 1.16.0. There are problems in prior versions due to DNS and VM(Hyper-V, VirtualBox). This version allows to run minikube as a docker container.
It can be download from here: https://github.com/kubernetes/minikube/releases Assuming you are not behind proxy or VPN (you may have network problems), following installation start minikube with this command.
You must have docker running.
minikube start --driver=docker
This will download images and start minikube. Then install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl
First we need rolebinding for querying API Server. Otherwise KubernetesClient cannot reach API Server. default is the namespace here.
kubectl create rolebinding default-sa-view --clusterrole=view --serviceaccount=default:default --namespace=default
Get example project
git clone https://github.com/gungor/springboot-k8s-configmap-reload-example.git
cd springboot-k8s-configmap-reload-example
Now add configmap named “k8s-live-reload-configmap” to kubernetes
kubectl apply -f src/k8s/config-map.yml
Switch to kubernetes docker daemon in active shell to make Kubernetes reach application image. Run the command below, then run the last command in the output.
minikube docker-env
Build application image
mvn clean install spring-boot:build-image
Deployment and service
kubectl create deployment liveconfig-demo --image=springboot-configmap-livereload-example:0.0.1-SNAPSHOT
kubectl create service clusterip liveconfig-demo --tcp=8080:8080
Test
Now see config before it has changed Deployment and service
kubectl get service liveconfig-demo #copy CLUSTER-IP returned from this command
minikube ssh
curl http://CLUSTER-IP:8080/liveconfigtest
It should return oldvalue. Now edit config map through command below or through minikube dashboard
kubectl edit configmap k8s-live-reload-configmap
After editing configmap, recheck application
minikube ssh
curl http://CLUSTER-IP:8080/liveconfigtest
It returns new value.