1

Hello I'm starting with docker and docker compose and I have the following problem:

I'm working in a spring micro services architecture where I have one configuration service, one discovery service, one gateway service and multiple resource services. To run these services, I build jar files, which I place in separated folder per service with their config files (application.yml and bootstrap.yml): e.g:

  • config-service/

    • config-service.jar
    • application.yml
  • discovery-service/

    • discovery-service.jar
    • bootstrap.yml
  • gateway-service/

    • gateway-service.jar
    • bootstrap.yml
  • crm-service/

    • crm-service.jar
    • bootstrap.yml

This works so far on my server.

Now I want to deploy my services in different environments as docker images (created with mvn build image and buildpack) using docker compose, where the configuration files vary depending on the environment. How can I deploy a service as a container using an existing image but with a different configuration file?

Thank you in advance!

Herval NGANYA
  • 135
  • 1
  • 13
  • 1
    You could put all your files in that image and then use enviroment variable to select the one that you want to use on run. Not sure if that would be good practice though. I think its better practice to do that on build via build arg and copy only the file you need. https://docs.docker.com/compose/compose-file/compose-file-v3/#build. – The Fool Aug 08 '21 at 18:09

1 Answers1

1

There are a few possibilities when handling configuration in a containerized environment.

One of the options is that Spring boot allows you to use environment variables for each application property. For example, let's say you have a spring.datasource.url property, in that case you could also define that property by setting a SPRING_DATASOURCE_URL environment variable:

version: '3.8'

services:
  my-spring-boot-app:
    image: my-image:0.0.1
    environment:
      - SPRING_DATASOURCE_URL=jdbc:my-database-url

Alternatively, you could use volumes to put an external file on a specific location within a container:

version: '3.8'

services:
  my-spring-boot-app:
    image: my-image:0.0.1
    volumes:
      ./my-app/bootstrap.yml:/etc/my-app/bootstrap.yml

In this example I'm copyingbootstrap.yml from a relative folder on my host machine, to /etc/my-app within the container. If you put these files within the same folder as your JAR file, you can override the configuration.

g00glen00b
  • 41,995
  • 13
  • 95
  • 133
  • 1
    Volumes to mount config in prod is a real bad idea. – The Fool Aug 08 '21 at 19:06
  • @g00glen00b Thanks a lot for you answer. I tried the first option which works perfectly. But the problem is that I have for my resource service multiple properties configured and some of these properties are the same for multiple services. I find it not so cool to repeat configurations and to have a lot of properties configured in a docker-compose file. For that reason, I would like to use the alternative you provided. But question: where do I find the jar file in the container? I just remind that that the image was generated using maven build-image. – Herval NGANYA Aug 09 '21 at 12:23
  • @TheFool Why is it not a good idea to to mount the config in prod? – Herval NGANYA Aug 09 '21 at 12:26
  • Because volumes are there to persist data. Not read configuration from. You will get more problems than you solve by doing this if you are planning to deploy your container in a cluster where it would move around nodes. The idea is to bake everything you need into the image so you can move it around with ease. In general its not good practice. I think enviroment variables or build args are better practice. – The Fool Aug 09 '21 at 12:53
  • 1
    I could improve the concept and build what I want. Thank you guys. Here is my concept: - I use environment variables - For each service, I create a separate file. e.g service1.env, service2.env, etc. - Then I call these files in the docker-compose.yml as follows: service1: env_file: - 'service1.env' - Then for shared service variables, I can either have a .env file in the same folder as the docker-compose file or add the file shared env file in the env_file section. https://stackoverflow.com/a/48651071/8182381 – Herval NGANYA Aug 09 '21 at 16:11
  • Just another question please. In my resource services, I have e.g a custom property app.my-url in my bootstrap.yml that I access in my app with @Value(""). Is it not possible to configure that also with environment variables? So far it does not work. – Herval NGANYA Aug 09 '21 at 20:07
  • @HervalNGANYA, I think you should be able to change your code to read directly the env var. If its not possible, what I have done in the past, I have read env vars in an `entrypoint` script and written it to file on container startup. I have written a blog post about entrypoints that may help you, if you really need to go that way. I would try to avoid it, if possible though. https://dev.to/codingsafari/advanced-entrypoint-techniques-for-docker-container-3dc – The Fool Aug 10 '21 at 06:50
  • @HervalNGANYA, Here is is what you are looking for maybe https://stackoverflow.com/questions/33125614/spring-boot-using-environment-variables-in-application-yml. I dont really write java apps, so I am not sure. – The Fool Aug 10 '21 at 06:57
  • @HervalNGANYA Properties within bootstrap.yml are a bit special. If you want to replace those with environment variables, you have to do something like this: https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html#_the_bootstrap_application_context – g00glen00b Aug 10 '21 at 21:32