Spring Cloud Config is one of the main projects under Spring Cloud and that’s mainly designed for centralizing the application configuration which is one of the needs come up with the microservices world as stated in the Twelve-Factor App Manifesto.
Why do we need such a centralized configuration management ?
In the microservices world, basically, each bounded context is implemented as separate microservices and scaled independently one from others. Briefly, that means numerous services each having its own configuration. And as you guess, management of these configurations manually and independently is a cumbersome work. For example, if a timeout value is to be increased then you must change the relevant property in all configurations of the deployed service; and worse, if the property is to be applied to several services that change may need to be applied to hundreds of configurations. That’s really quite awesome. You can think of this scenario using the following simple microservice arcitecture diagram.
So the config server solution comes to play to resolve this problem by the way of keeping all the configuration in one place and serving them to all services on demand.
That means centralizing all the application configuration in one place and that again means changing a configuration property would be applied once in the data store of the config server regardless of the count of services deployed; saves your time and so the money.
Another benefit gained from the config server solution is that you can easily refresh a property by changing it in one place and apply it to the application on runtime without need a restart of all the instances of the services. Yes, that’s exactly perfect.
Spring Cloud Config Architecture
After explaining why it’s needed, it’s time to look over how the config server architecture works. Here is the simple diagram of the config server architecture.
Let’s dive into the config server architecture diagram:
- The configuration properties of the application is kept on a data store such as Git, database or some other kind of data source.
- The default data store is configured to Git via Spring autoconfiguration and can be configured to some other data store such as an RDBMS.
- Config Server reads the application properties from the data store and serves them to the clients.
- Config clients are configured to read the application properties from the config server instead of from a local properties file.
- When the Spring Boot client application is bootstrapped, it requests the properties from the config server and loads them all into the PropertySources in the Spring application context as key-values.
- These key-values becomes accessible via Spring’s Environment interface to the other Spring components just as in the Spring Property Management you already know and can be used as:
- autowiring Environment interface
- using @Value annotation
- using @ConfigurationProperties
Spring Cloud Config Server
Config Server is capable of serving all the configuration properties of an application in all environments.
Let’s exemplify a typical use-case:
- Application properties of development, test and production environments are kept in different branches on a git repository, each branch is for different environment.
- A client from test environment makes a request to the config server by providing the label as test within its input. In this case, the config server provides the configuration data from the branch test.
- In this scenario, the config server is located as a central server accessible from all environments.
- As an alternative to this reference scenario, one can design its architecture as config server per environment if environments are designed as different networks. In this case, you can again keep your configuration data in a single git repository and as different branch for each environment but different config server deployments for each environments located in different networks. This is also possible with Spring Cloud Config.
- For an alternative scenario, basically, one can seperate the properties of each environment using profiles.
Git Config Repository Naming Conventions
When a git repository is used as data store, property files are created according to the following rules:
- application.properties / application.yml
This is the common properties file for all config client applications.
When a file based repository, such as Git, is used then the files beginning with name application is shared to all applications wired to the same config server. - [application-name].properties / [application-name].yml
Configuration data specific to an application is stored in a file named with the application name of the client. - [application-name]-[profile].properties / [application-name]-[profile].yml
Configuration data with respect to a specific profile can be stored in a file named with profile after application name separated with a dash.
Config Server Url
When a config client wants to read the configuration data from the config server, the config client makes a request to the config server with a url named config server url and gets the relevant configuration data as json response.
The config server url is formed of the following structure:
http://config-server-host:port/[application_name]/[profile]/[label]
You can also test your config server by making this request from your browser and analyze the response yourself.
Let’s look over each part of this url:
- application
- Client application sets the spring.application.name property in the bootstrap.properties file and this is used as the first parameter in the config server url.
- Config server url tells the config server that the config data is to be fetched first from a file whose name begins with the application name parameter in the url.
- profile
- Client application sets the spring.profiles.active property in the bootstrap.properties file and this is used as the second parameter in the config server url.
- Config server url tells the config server that the config data is to be fetched preferably from files whose name contains the profile in the url.
- This parameter is optional and the default value is default.
- An active profile set in the properties file overrides the default profile.
- In case of db backend, default profile must also be implicitly set.
- In case of multiple active profiles in client applications, last-wins strategy is applied and profiles override each other’s properties.
For example;spring.profiles.active = test, cluster2
This definition means that; if a property is defined both in application-test.properties and application-cluster2.profiles, then the latter one overrides the former one.
- label
- label is the third parameter in the config server url and it is also optional with the default value as master which references the master branch of the repository in case of git.
- label corresponds to branch when using git or any other version control system as backend.
- Client application can also set the spring.cloud.config.label property in the bootstrap.properties file and this is used as the third parameter in the config server url, telling the config server from which branch the config data must be fetched.
- label can be used for grouping the properties by environments like develop, test and master.
Configuration Overriding
A configuration data defined in a properties file can be overridden with a more specific one. The following diagram basically shows this:
The general rules are as follows:
- A configuration in the application.properties can be overridden with the properties file named with the application itself.
- A configuration within a file specific to a profile overrides the general one.
For example, when the active profile is set as cluster2; the property abc in a file named application-cluster2.proeprties overrides the property abc in a file named application.properties.
Config Server Application
To make a Spring Boot application act as a config server we do the followings:
- add config server dependencies to pom.xml
- enable config server with an auto-configuration annotation
- configure bootstrap properties for config server
Dependencies for Config Server
We need to add the following dependencies to the pom.xml of the Spring Boot config server application for the most basic configuration.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
Enabling Config Server
To enable the auto-configuration of config server in a Spring Boot application we add the @EnableConfigServer annotation supplied by Spring Cloud.
@EnableConfigServer @SpringBootApplication public class ConfigServerGitApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerGitApplication.class, args); } }
Config Server Properties
In a file named bootstrap.properties in the config server application, the reference to the data store is set via the use of auto-configuration properties as follows:
###############LOCAL REPOSITORY######################## #spring.cloud.config.server.git.uri = file:///home/erol/dev/app_data/config-repo ###############GITHUB REPOSITORY####################### spring.cloud.config.server.git.uri = https://github.com/erolhira/config-repo-sample.git #spring.cloud.config.server.git.username = my-user-name #spring.cloud.config.server.git.password = my-password
About Bootstrap Context
In a Spring application, Spring-managed objects like Spring beans, properties and etc. are held in the Spring application context which is a container for objects having their lifecycles managed by Spring.
In a Spring Cloud application, on the other hand, there is also a bit more inclusive cloud context named bootstrap context. A bootstrap context is the parent context of all the Spring Boot application contexts configured with the same config server and this context is responsible for loading the configuration properties from the config server.
In a Spring Cloud application, initial configuration properties are kept in a file named bootstrap.properties.
In the following diagram, you can see the relation between the two contexts and their property sources.
The default precedence over the property sources is as follows:
Bootstrap Context > Application Context
Config Server > bootstrap.properties > application.properties
Config Client Application
A Spring Boot application that’s configured to load its configuration properties from a config server is called a config client. The configuration to be made in the bootstrap.properties for the config client is as follows:
- spring.application.name
This is the logical name of the application and maps to the first parameter in the config server url. Config server returns data to the config client by reading from the files starting with this name as high priority. - spring.cloud.config.uri
This property defines the config server uri which forms the base of the config server url. - spring.profiles.active
This property defines the active profiles. In case of multiple active profiles, last-wins strategy is applied and profiles override each other’s properties.
spring.application.name=myconfig-client-app spring.cloud.config.uri=http://localhost:8888 spring.cloud.config.server.git.clone-on-start=true spring.profiles.active=cluster2,instance01
Dependencies for Config Client
We need to add the following dependencies to the pom.xml of the Spring Boot config client application for the most basic usage.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
Running the Config Server
So now, we first run the config server application and type in the browser:
http://localhost:8888/myconfig-client-app/cluster2
As you see, the url does not contain the third parameter which is the label and its default value is master, so here; the configuration data is going to be fetched from the master branch.
And here is the result:
As you see, when you use a property binding in your client application, the value of the property is selected from the highest priority file that can be selected.
According to the example above; if you wire the prop2 in the config client, then it’s value is taken from the myconfig-client-app-cluster2.properties, not from the application.properties.
You can see this by running the sample config client application in my github page and try some alternatives to understand the concept better.
Overriding Remote Properties
By default, the properties taken from the config server overrides the ones in the local property files.
However, if you want the local ones take precedence over the remote ones, then the following properties have to be defined in a remote property file.
spring.cloud.config.allowOverride=true spring.cloud.config.overrideNone=true spring.cloud.config.overrideSystemProperties=false
Summary
In this article, we have looked over the Spring Cloud Config solution architecture and how can it be applied with Git repository.
For further, you can inspect how can it be applied with a jdbc backend instead of Git.
And in the next step, you can work on refresh strategies from basic actuator /refresh endpoint calls to a bit more complicated Spring Cloud Bus integration with streaming solutions like Kafka or Rabbit MQ.
Sample Code
You can see the sample code for this article in my github page, both for the config server and the config client.
https://github.com/erolhira/spring-cloud-config
References
https://spring.io/projects/spring-cloud-config
https://cloud.spring.io/spring-cloud-config/reference/html/
https://cloud.spring.io/spring-cloud-static/Hoxton.RELEASE/reference/html/spring-cloud-hoxton-configprops.html