Externalizing properties of a spring boot application on docker
If you've decided to containerize your spring boot application, this will probably be the first task on your list.
Externalizing your application properties will make your application portable between production and dev environments. As a good practice, your container should be immutable and all environment configuration should be externalized.
There are multiple ways to achieve this end goal.
1) First and the most recommended way is to build a spring cloud config server and configure a client on your application to consume the configuration on startup. This way, any changes to configuration can be made by refreshing the cloud config server and not restarting the client.
2) Easier method explained in this article: If you are just experimenting with docker, just deploying it on your local machine or don't want to go through the hassle of making code changes, you can do so by declaring environment variables in your docker-compose. Since environment variables take precedence over application.properties (or .yml), they can be passed in your docker command to launch a container with your desired configuration. Lets explore this method a little further.
Sample spring boot application
I've created a sample spring boot application, that publishes a message to rabbitmq when an api is called. It's a really basic application which has some rabbitmq properties in the application.properties file. Please feel free to clone this application from github.
Lets take a look at the application.properties file.
# Rabbit MQ properties
spring.rabbitmq.host = localhost spring.rabbitmq.port = 5672 spring.rabbitmq.username = guest spring.rabbitmq.password = guest resolute.rabbitmq.publishQueueName = resolute-run-request resolute.rabbitmq.exchange = resolute
Below is the docker-compose for the application. You can click here to download it from my repo
As you can see in the docker-compose file above, I'm trying to bind a rabbitmq container to my application at runtime and hence overriding the rabbitmq host name property while creating the container.
Thats it! You can use the template above to override any application property and deploy your container. You can also ask your dev-ops engineer to create a pipeline that builds the docker-compose file with desired properties at runtime and create containers galore.
Tip for dev-ops engineers: As a best security practice, sensitive properties like usernames, passwords and api tokens must be stored as secrets in encrypted secret management stores like Hashicorp's vault or AWS secrets manager or docker secrets. Its not recommended to pass them through a pipeline variable.
PS: I'll try to publish another article on how to bind services to spring boot apps using docker-compose if time permits.
CamelCase and dashes in the spring property name is a nightmare for docker compose (version 3.7). The only way to override is to use SPRING_APPLICATION_JSON, like this: SPRING_APPLICATION_JSON={"eureka":{"client":{"serviceUrl":{"defaultZone":"http://eureka-server:8761/eureka"}}}} . But what to do if I have to override 2 properties for the same service: one with camel case, another with dash?
Thank you.