How to do Spring-boot configuration for many clients - spring

I am wondering how to resolve problem: I have a spring-boot app on docker that connects to db and some other service.
Probably some clients will have db on other urls than the others.
I use spring.datasource.url property to connect to DB. Should I add it to args and use:
Properties properties = new Properties();
properties.put("spring.datasource.url", args[1]);
application.setDefaultProperties(properties);
And something like that will override it ? But every run will need adding DB url. Or use something else?

datasource could be read as a variable from the docker-compose file:
assume this is your docker-compose file:
version: '2'
services:
db:
image: customimage_mysql
restart: always
ports:
- "3306:3306"
application:
build: .
ports:
- "9111:9111"
depends_on:
- db
links:
- db
environment:
- database.url=jdbc:mysql://mysql-docker-container:3306/spring_app_db?
Now you have 2 options:
set different values for databse.url inside docker compose and build image for each app correspondingly
set different variables (databse1.url , databse2.url,databse3.url, ...) inside docker-compose file, and reference to them from
application.properties:
application.properties
spring.datasource.url=${database.url}
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
server.port=9111

According to the information that you have provided here, the database link should be a configuration to your application. basically you need to have a configurations file
application.properties
And when you want to change the URL, just change it in the configuration file and build.
you can find the documentation here
And moreover if you are using devops environment like kubernetes, you would have to have a config-map and your deployments will get configurations from those config-maps which are like application.properties files.

If you've got lots of deployments each with their own database then that will take some management one way or another. But you don't want it to require lots of builds of your app - you want to externalise that configuration.
Sorting boot has features for externalising configuration (https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html). The simplest for your case would be to use environment variables that override properties by relaxed binding of names (https://github.com/spring-projects/spring-boot/wiki/Relaxed-Binding-2.0). If app is started with an environment variable named SPRING_DATASOURCE_URL then this value will override what you have in your properties for spring.datasource.url. Your properties file effectively sets a default value that you can override. This is out of the box behaviour for Spring Boot and applies to other properties too (inc all the db ones, though if you've got databases of different types then you'll want to include all the relevant driver jars in your build).
Since you're using docker you can set environment variables in the container at deploy/startup time using a -e parameter. So you can override at deploy time for each deployed instance.
You might well use further layers on top of docker like docker-compose or Kubernetes. Then you might get into setting the environment variables in deployment descriptor files that describe your deployment configuration. But that configuration management question is at a different layer/stage and is no longer part of the build step once you have your config externalised.

Related

Environment variables for Spring Cloud Config in Docker

So, I am learning about microservices (I am a beginner) and I'm facing an issue. I've went through the Spring Cloud Config and Docker docs hoping to find a solution, but I didn't.
I have an app with 3 microservices (Spring Boot) and 1 config server (Spring Cloud Config). I'm using a private Github repository for storing config files and this is my application.properties file for config server:
spring.profiles.active=git
spring.cloud.config.server.git.uri=https://github.com/username/microservices-config.git
spring.cloud.config.server.git.clone-on-start=true
spring.cloud.config.server.git.default-label=master
spring.cloud.config.server.git.username=${GIT_USERNAME}
spring.cloud.config.server.git.password=${GIT_ACCCESS_TOKEN}
I have a Dockerfile based on which I have created a Docker image for config server (with no problems). I created a docker-compose.yml which I use to create and run containers, but it fails because of an exception in my cloud config app. The exception is:
org.eclipse.jgit.api.errors.TransportException: https://github.com/username/microservices-config.git: not authorized
Which basically means that my environment variables GIT_USERNAME and GIT_ACCCESS_TOKEN (that I set up in Intellij's "Edit configuration" and use in application.properties) are not available for the config server to use in a container.
The question is: Do I need to somehow add those environment variables to .jar or to Docker image or to Docker container? Like I'm not sure how do I make them available for the config server to use in a container.
Any help or explanation is welcomed :)

Spring Boot Log initialization with Spring Cloud Kubernetes

Spring Boot 2.2.6-RELEASE
In my application.yml, I have this line :
logging.config: classpath:my-logback-config.xml
This works well, spring get its config nicely
In my my-logback-config.xml I have this line :
<springProperty name="LOG_HOST" source="config.logHost" />
<springProperty name="LOG_PORT" source="config.logPort" />
Again, this works well, it get its value from an external config file, which is defined in a ENV variable
SPRING_CONFIG_ADDITIONAL_LOCATION=file:/my-env.properties
But when I enable Spring Cloud Kubernetes, this fails, with an UnknowHostException : "LOG_HOST_IS_UNDEFINED" cannot be resolved. (the value of LOG_HOST is used to setup a network appender)
Why does enabling Spring Cloud Kubernetes change the behavior of logging initialization?
It seem that values from SPRING_CONFIG_ADDITIONAL_LOCATION are not loaded yet.
I can't load this value from a configMap, since Spring Cloud Kubernetes has not been initialized at the moment logging is being initialized.
Finally, the problem was that the ENV var SPRING_CONFIG_ADDITIONAL_LOCATION was set to a folder, and not to a file on container.
Locally, on windows, setting 'SPRING_CONFIG_ADDITIONAL_LOCATION' to either a file or a folder seems to work, but in the Docker image (RH linux), it has an impact.
When SPRING_CONFIG_ADDITIONAL_LOCATION is set to a folder, values of the enclosed ".properties" files are ignored.
I can reproduce (fix) the issue by changing my docker file :
ENV SPRING_CONFIG_ADDITIONAL_LOCATION="/mnt/properties/application.properties"
to
ENV SPRING_CONFIG_ADDITIONAL_LOCATION="/mnt/properties/"

Externalize application configuration for Google Cloud Run

I was looking to externalize application configuration for containerized applications on Google Cloud Run. I know there are environment variables available for cloud run application and I want to have something as Config Server for Cloud Run.
Is there any out of the box support available on GCP?
When setting up your Cloud Run deployment, you can simply inject environment variables into your service:
Because Spring Boot comes with application.properties mechanism, you can easily override those values exactly from the environment variables. Do keep in mind, that the syntax is slightly different:
application.properties
spring.profiles.active=dev
environment variables
SPRING_PROFILES_ACTIVE=dev
Injected env variables will take precedence over the ones defined in your application.properties file.
There are two solutions to it :
If your docker file is "ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/****.jar"]" then use "-Dspring.profiles.active=dev" in the container arguments on the cloud run.
In case your docker file has "CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/***.jar"]" You can do it by setting Environment Variable as SPRING_PROFILES_ACTIVE and value as dev in "Variables & Secrets" tab on cloud run Container Configuration

How to specify an external application.yml in spring with profiles

From the spring documentation http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-yaml i see that an external YAML file is possible.
I was able to use a PropertyPlaceholderConfig FileSystem resourse to load in yaml, but it did not honor the active profile.
I saw for application.properties you can use #PropertySource, but that does not work for YAML according to the docs.
So bottom line question: How do a specify an application.yml in a profile aware fashion in Spring4/spring boot.
Note: It works in src/main/resources/application.yml
In order to specify an external profile aware .yml file the SPRING_CONFIG_LOCATION and SPRING_PROFILES_ACTIVE system variables can be used.
JAVA_OPTS example
-Dspring.profiles.active=dev -Dspring.config.location=file:C:/application.yml
This will allow you to have provide multiple profiles inside of a YML file and let spring do the heavy lifting of evaluating the correct properties:
spring:
profiles: dev
someprop: devprop
---
spring:
profiles: test
someprop: testprop

Spring 3.1 Profile: how to set in Stackato Tomcat container

I'm using Spring 3.1.3 and the new profile feature. When I set the environment in my IDE for spring_profiles_active=NONPROD, it works fine. However, when I deploy to our aPaaS environment which is also using Tomcat, it isn't getting picked up.
Shouldn't I just be able to do the following:
env:
CATALINA_OPTS: -Dspring_profiles_active=NONPROD
If I ssh to the machine, I see this is getting set. Any ideas why Spring isn't picking this up?
Put the following lines to your manifest.yml file to get the Spring profile activated in Stackato:
env:
spring_profiles_active:
default: NONPROD
This will put spring_profiles_active into environment variable and Spring happily reads it from there. Note that you have to use underscores in the variable name, because Stackato doesn't like dots in those. The reason is that Linux environment variable names shouldn't contain dots for shell programs to work correctly with them.

Resources