My favourite way to override a Spring property at runtime is with environment variables. They are simple and flexible, and easy to add to a Kubernetes Deployment.
Properties externalise your application’s config.
Properties are a way of decoupling your application from its runtime configuration. Properties let you run the same application, in lots of different environments, without having to make changes to the code itself.
Setting properties in Spring Boot
In Spring Boot, you normally set initial values for properties in a file called…
To set different properties, you could define more than one properties file, and use a feature called Spring profiles to switch between them.
But I think a far cleaner way is to override the properties which you want to change in each environment. Plus, it means that you don’t need to worry about storing a bunch of properties files with your source code.
There are a few different ways that you can override the properties of a Spring Boot application at runtime, but I think that the best way is to use environment variables.
Environment variables have been around forever, and they’re a well-known way to store some values that should change the behaviour of applications.
For example, you might set the
JAVA_HOME environment variable to point to your Java installation.
Fortunately Spring Boot respects environment variables as a source of configuration for your app.
Using environment variables with Spring Boot
In Spring Boot, any property can be overridden by an environment variable of the same name, with the characters changed to upper case, and the dots changed to underscores.
So, in practice, that means a property which is defined like this in your
…can be overridden by setting an environment variable like this:
This means that if we want to override any property, we can do it by setting an environment variable in the container. In Kubernetes, we do this by updating the Deployment.
Kubernetes loves environment variables
I think environment variables are one of the easiest ways to provide configuration to any app in Kubernetes. There’s first class support for env vars in Kubernetes.
And they are highly visible too. So if a developer or administrator needs to debug a Pod, they see instantly which environment variables have been set on the container. They don’t need to know the quirks of how your Java app receives configuration.
For example, you can view all the environment variables on any Pod using:
kubectl describe pod <pod-name>
You won’t know how helpful this feature is, until you run into a problem that you need to start debugging! Often, discovering an application’s runtime configuration is half of the battle. Environment variables simply make step that much quicker.
With that in mind, let’s look at how to set environment variables on a Spring Boot app in Kubernetes.
How to override Spring Boot properties in Kubernetes using environment variables
To override your Spring Boot application properties when it’s running on Kubernetes, just set environment variables on the container.
To set an environment variable on a container, first, initialise a ConfigMap containing the environment variables that you want to override.
Create a ConfigMap
First, you want to create a ConfigMap, containing the properties that you want to override. Each of the properties should be upper-case, and with dots (
.) converted to underscores. It should look something like this:
apiVersion: v1 kind: ConfigMap metadata: creationTimestamp: null name: my-config data: ADMIN_PASSWORD: 111111hiya FAVOURITE_COLOUR: green FAVOURITE_FOOD: eggs
If you don’t want to write the YAML yourself, you can use
kubectl create configmap which will generate the YAML for you. If you define your properties in an environment file, e.g.
app.env, then if you run this command, and
kubectl will create the configmap YAML for you:
oc create configmap my-config \ --from-env-file=app.env \ --dry-run=client -o yaml > configmap.yml
Now apply the ConfigMap to your Kubernetes cluster.
oc apply -f configmap.yml
Next we’ll attach the ConfigMap to environment variables in a Deployment.
Attach the ConfigMap to your Deployment
To make sure the environment variables are set on the Spring Boot Pod, update the object which creates the pods. This is usually a StatefulSet, Deployment, or DeploymentConfig in OpenShift.
In these objects, you can give a list of environment variables that will be set on the Pod.
spec.containers.env section to populate individual environment variables. In this example, I’m using the
valueFrom section to set the env vars I defined above:
apiVersion: apps/v1 kind: Deployment metadata: labels: app: my-spring-boot-app name: my-spring-boot-app spec: selector: matchLabels: app: my-spring-boot-app template: metadata: labels: app: my-spring-boot-app name: my-spring-boot-app spec: containers: - env: - name: ADMIN_PASSWORD valueFrom: configMapKeyRef: name: my-config key: ADMIN_PASSWORD - name: FAVOURITE_COLOUR valueFrom: configMapKeyRef: name: my-config key: FAVOURITE_COLOUR - name: FAVOURITE_FOOD valueFrom: configMapKeyRef: name: my-config key: FAVOURITE_FOOD image: jsmith/my-spring-boot-app:1.0 imagePullPolicy: IfNotPresent name: my-spring-boot-app ports: - containerPort: 8080 protocol: TCP
configMapKeyRef bits. They point to my ConfigMap called
Kubernetes will look for each
key in the ConfigMap, and set its value as an environment variable in the container.
Now, when your Spring Boot application starts, it will be given those environment variables, which will override your
One last tip
When I’m developing microservices with Spring Boot, and deploying them in multiple environments, I often need to know exactly what configuration an application is running with.
Fortunately, you can list all Spring Boot properties using the Actuator, which can be really helpful when troubleshooting! (I use this all the time.)
Over and out.