How to Override Any Spring Boot Property in Kubernetes
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.
In this article we’ll see how to use properties and set them at runtime, when you’re deploying to Kubernetes.
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… application.properties
.
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
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 application.properties
:
database.username
…can be overridden by setting an environment variable like this:
DATABASE_USERNAME
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.
Use the 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
Notice the configMapKeyRef
bits. They point to my ConfigMap called my-config
.
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 application.properties
.
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.