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.

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.

Comments

Got any thoughts on what you've just read? Anything wrong, or no longer correct? Sign in with your GitHub account to leave a comment.

(All comments get added as Issues in our GitHub repo here, using the comments tool Utterances)