I want to use a common application properties file for multiple microservices which will have some common configuration like DB Source config etc..I have use the config Server with Eureka server and zull Proxy.
Issue:
When using configServer we need to provide the spring.application.name = 'xyz'
which in turn find the xyz.properties for this microservice configuration.
The same way when we register the service with zuul proxy also need the same application name for configure the service path as zuul.routes.xyz.path = /iii/*.
Now I want that multiple service will share the same property file(xyz.properties) but need to register the zuul route as well so I have to provide the different name for each service. If I will provide the different name to each service they will not be able to locate the same property file.
I am new to spring boot micro services.
spring.config.client.name supports multiple names separated by commas to load the configuration properties.
In this case, store the common properties in common.yml and xyz properties in xyz.yml. Finally, mention spring.cloud.config.name: xyz,common
spring:
cloud:
config:
uri: http://localhost:8888
name: xyz,common
Output:
Fetching config from server at : http://localhost:8888
Located environment: name=xyz,common, profiles=[default], label=null, version=91edcf96c6a88707bf39014a16ad5d301d6b4575, state=null
Located property source: CompositePropertySource {name='configService', propertySources=[MapPropertySource {name='configClient'}, MapPropertySource {name='https://github.com/BarathArivazhagan/config-server-repository/common.yml'}, MapPropertySource {name='https://github.com/BarathArivazhagan/config-server-repository/xyz.yml'}]}
I would like to point out that the provided solution leverages the "spring.config.client.name" client side property semantics to achieve a config server behavior of serving properties files from multiple files other than application[-profile].* and {appname}[-profile].*
However, note that for a simple case and considering a root dir, the config server serves properties from files defined in this root dir or under a folder with the name of the application, that the property files under it correspond to, i.e. */{appname}/application[-profile].** or */{appname}/{appname}[-profile].**
The "spring.config.client.name" environment property instructs the config server which application names the requesting app matches with. This means that given a spring.config.client.name=a,b , the config server will assume serving properties defined for app (with name) a and b to the requesting app! This is not the exact same thing as I want my properties been served from file names a and b! Therefore we are abusing the property semantics for managing our config server serving from the file names we would like it to.
However, due to the actual semantics of spring.config.client.name the config server will serve everything applicable from
/a[-profile].*
/b[-profile].*
/a/{applicable names}
/b/{applicable names}
The caveat here is that we achieve what we want only for the root directory and, moreover, if we have a configserver that serves multiple springboot apps we loose the ability to have all our properties under our application's name-folder.
Even worse, if there exists another app (or -attention!- will exist in the future) with the same name as one of our desired property file names, the config server will start serving to our app ALL the configuration defined for that other app!!! This could end up in wrong and even harmful served configuration!
(I repeat it will serve everything applicable under /{other-app-name-that-i-happened-to-use-as-filename-and-defined-it-through-spring.config.client.name}/*!!!)
So beware when pirsuiting this approach!
I have issued a pull request for spring-cloud-config-server 1.4.x, that supports defining additional file names, through a spring.cloud.config.server.searchNames environment property, in the same sense one can do for a single springboot app, as defined in the Externalized Configuration.Application Property Files section of the documentation, using the spring.config.name enviroment property. I hope they review it soon
Related
I am trying to revamp my microservice to maintain a single application yaml rather maintaining multiple profiles. Initially I was maintaining different profiles and the common configurations were repeated across the helm environment specific values yaml. Now the strategy is to move everything to values.yml and maintain environment specific values in config map. The problem I face is my application yml now looks very generic with placeholders and for the same reason the test runs fails as I cannot give a default value for each of the configurations in application.yml. The reason being, For Eg: mongodb cluster endpoint format is different in local to other environment. I managed to place a local specific yaml file under test/resources, but not sure it's the right approach. I need to anyway maintain a local specific yaml under main/resources for running locally. So essentially I am duplicating it under test resources as well. Is there any better way of pointing test to load the application-local.yml under main resources so that I can avoid the duplication or is there any better way of doing this as a whole?
1. Working with multiple configs in One File
You can add all your configurations in one property file as illustrated below
spring.application.name: test. ## Used for all profiles
---
spring.config.active.on-profile:dev
spring.database.host: localhost
spring.database.name: testing
---
spring.config.active.on-profile:prod. ##You can use spring.profiles:prod
spring.database.host: localhost
spring.database.name: testing
---
--- marks where yml document splits, while #--- marks where properties file splits.
Multi-document property files are often used in conjunction with the following activation properties
spring.config.activate.on-profile
spring.config.activate.on.on-cloud-platform
All property definitions defined without specifying the profile name are used on all profiles. In the above case spring.application.name will be used on all profiles dev or prod.
When running the application you can manually specify profile or you can set in within the yml or properties on properties that are used throughout the application.
spring.application.name: test
spring.profiles.active: prod
2. Testing your application
when running tests that need to access properties in yml(property)file there is
no need to redefine your configurations.Just add #ActiveProfile("profile-name")
on your tests.
for example:
#ActiveProfiles("dev")
#SpringBootTest(webEnvironmentSpringBootTest.WebEnvironment.RANDOM_PORT)
Using spring cloud config properties can be defined for different services and different environments, e.g. using a native profile we could have the following tree in the server:
resources
config
service-a
service-a-local.properties
service-a-test.properties
service-b
service-b-local.properties
service-b-test.properties
and have client services bootstrapped with configuration from the server, using one of the available options, such as #Value annotations etc. This however will only see the properties slice from the config server for the calling service (or whatever spring.application.name is used).
How can service-a access properties of service-b (or any other service) dynamically? The default property source locator uses a "/{name}/{profile}" path for fetch requests. I suppose one could restructure the entire configuration and put all services' properties in one file per environment, using some appropriate naming convention for the properties (e.g. using the service name as the prefix), and then explicitly prefix the calling-site property references with that prefix, but is there another/more elegant option, before using a discovery/mesh alternative?
My Spring Boot app will have 4 different environments:
Local; running locally on my machine
Dev
UAT
Prod
When a new user registers for my app, the backend sends them an email to verify their address/account. In this email there will be a link; the user clicks the link which verifies them in the database and allows them to now login and use the app.
These links of course have to have the environment built into them:
Locally, the link might be http://localhost:9200/v1/data/accounts/verify?vt=12345
In dev the link might be: http://dev.myapp.example.com/v1/data/accounts/verify?vt=12345
In UAT the link might be: http://uat.myapp.example.com/v1/data/accounts/verify?vt=12345
In Prod the link might be: http://myapp.example.com/v1/data/accounts/verify?vt=12345
In all three environments, the hostname + port are different. Locally I specify localhost:9200 (both localhost + port). Non-locally I don't need to specify port because the app will be running on nodes behind a load balancer. In production I don't need an environment-specific subdomain like dev or uat.
In order for my emails to work correctly in all 4 environments, I need to set an environment variable that is then used by my email generator to generate links correctly.
I could use something homegrown, such as a custom property in application.properties like emailDomain, and set the property different in each environment's properties file.
But I feel like the smart folks that make up the Spring Boot community have probably already solved this problem for me...have they? Is there already a Spring Boot app property I can set that will take care of all this for me?
In the comments, I read that your main concern is being able to update the property without having to modify your .JAR/.WAR or changing some code.
This is possible since you can externalize your Spring boot configuration. If you check the Externalized Configuration docs, you can see that it looks for properties within:
OS environment variables.
...
Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
Application properties outside of your packaged jar
(application.properties and YAML variants).
Application properties packaged inside your jar (application.properties and YAML variants).
So, ideally, you can put an application.properties file next to your JAR, and update the properties in that file depending on the environment you run on.
I currently have a number of deployable applications that work in a distributed fashion to solve a business problem. We are currently using a number of property configuration files to provide changing configuration per environment based off a system environment variable. All these deployable application share common configuration for database and messaging. This is currently achieved by picking up property files from the class path and having both deployed apps share a common jar for each connection (db, jms) containing property files.
I am looking to start using Spring Config Server to externalize this configuration if possible. I have a question about how to share this common config.
Currently it looks something like this:-
Web1
- database
- jms
Messaging1
- database
- jms
In this situation both deployed apps share the same connections and these connections change per environment (lab, prf, prd, etc). How can I achieve the same with the Spring Configuration Server where I have app config for each deployable app?
Application.yml
Web1.yml
Web1-dev.yml
Messaging1.yml
Messaging1-dev.yml
If a connection property changed for an environment I would need to make the change to each deployable app configuration rather than making it just once.
Is there currently anyway to achieve this? Am I just missing a simple point?
I found working solution here https://cloud.spring.io/spring-cloud-config/single/spring-cloud-config.html, paragraph "2.1.5 Sharing Configuration With All Applications". It says:
With file-based (i.e. git, svn and native) repositories, resources
with file names in application* are shared between all client
applications (so application.properties, application.yml,
application-*.properties etc.). You can use resources with these file
names to configure global defaults and have them overridden by
application-specific files as necessary.
You should create application.properties or application.yml at the top level of configuration repository (if it is git or svn based). Don't forget to commit the changes.
This is how I have configured for my setup.
1 All Common properties across all services and environments will be in root->application.properties files
2 All Common properties across all environments specific to service will be root->service-X.properties files
3: Similarly, to have common properties across specific environment use env->application.properties file
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri:[git repo]
search-paths: /,/{profile}/
Finally found a solution. It's buried in the issues at github ...
https://github.com/spring-cloud/spring-cloud-config/issues/32
It worked liked described. I only noticed, that you need to put the files in a /config folder to make it work. If you put it in the root the file ist used by the configserver itself and is not included in the config requests.
application.properties/application.yml will be shared across all applications.
application-DEV.properties/application-DEV.yml will be shared across all DEV environment applications. You can replace DEV with any spring profile.
{applicationName}.properties/{applicationName}.yml will be shared across the give application.
Does anybody knows if it is possible to expose more than 1 property file per application in Spring Cloud config server?
For example I would like to have defined in my git repo properties for the same app, but in different files:
myapp-customer-services.yml
myapp-products-services.yml
and have all those properties defined inside the files, exposed under "myapp".
No that's not possible currently. I'm not sure it really makes much sense to be honest, since you can easily clearly delineate different sets of properties within a YAML file using separate documents.
Yes it is possible to expose more than 1 property file per application in Spring Cloud config server
You can access it in you client by using following properties
first specify profile which you want
example
myapp-customer.yml
myapp-products.yml
spring.profiles.active=customer,products
spring.cloud.config.name=myapp