Search results
Centralized and versioned configuration using Spring Cloud Config Server and Git
Spring Cloud Series
Subscribe to my newsletter to receive updates when content like this is published.
- Developing Microservices using Spring Boot, Jersey, Swagger and Docker
- Integration Testing using Spring Boot, Postgres and Docker
- Services registration and discovery using Spring Cloud Netflix Eureka Server and client-side load-balancing using Ribbon and Feign
- Centralized and versioned configuration using Spring Cloud Config Server and Git (you are here)
- Routing requests and dynamically refreshing routes using Spring Cloud Zuul Server
- Microservices Sidecar pattern implementation using Postgres, Spring Cloud Netflix and Docker
- Implementing Circuit Breaker using Hystrix, Dashboard using Spring Cloud Turbine Server (work in progress)
1. OVERVIEW
The previous blog post covered Service Registration and Discovery as an infrastructure service used in a microservice architecture. In this post I’ll review another infrastructure microservice, the Configuration management service.
Configuration is used to prevent hard-coding values in the applications. But it’s also used to specify what is expected to be different between deployment environments (qa, staging, production, …) such as host names, mail and database credentials and other backing services. The latter type of configuration is identified as one of the elements in The Twelve-Factor App.
The benefits of this practice are that it promotes building only one artifact, only one binary to be executed in all the environments. You should never have to build a different executable for each environment, this will most-likely cause troubleshooting and debugging headaches.
As part of the Spring Cloud Series, this post describes the Spring Cloud Config’s server and client usage, the configuration storage options and its relation with the Discovery Server in a registration-first and configuration-first approaches.
2. CONFIGURATION FIRST vs REGISTRATION FIRST
The Configuration server could be used as a standalone server, without any other infrastructure service, all is needed to know is its URL. However it could also be used with the Discovery server in two ways:
-
In a configuration-first approach, the client application connects to the Config server via the property spring.cloud.config.uri either set in a bootstrap file (
bootstrap.yml
orbootstrap.properties
) or as a environment variable. The Eureka server URL would be configured in a property served by the Config server and the client application can now discover dependent services. -
In a registration-first approach, the Config server registers with the Discovery server similarly to as other services do and the client application can bootstrap the Config server metadata using the applicable discovery settings. The benefits of this approach is that the client application only need to know the service name of the Config service. The disadvantage is that a extra network round trip is needed to get the Config service metadata before the client application can connect to it to get the properties.
Registration first |
3. REQUIREMENTS
- Java 7+.
- Maven 3.2+.
- Familiarity with Spring Framework.
- A Eureka server instance for the Demo Config client and the Config server in a registration-first approach to register with.
4. CREATE THE CONFIG SERVER BACKED BY A GIT REPOSITORY
This command will create a Maven project in a folder named configserver
with most of the dependencies used in the accompanying source code for this post.
Alternatively, it can also be generated using Spring Initializr tool then selecting Actuator, Config Server and Eureka Discovery dependencies as shown below:
Spring Initializr - Generate Config Server
The most relevant sections of Config server’s pom.xml
are shown below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
...
<properties>
...
<start-class>com.asimio.cloud.config.ConfigServerApplication</start-class>
<spring-cloud.version>Camden.SR3</spring-cloud.version>
...
</properties>
...
<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>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
...
<build>
...
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
...
This pom file inherits from Spring Boot and defines Spring Cloud dependencies management as a BOM. spring-cloud-config-server brings the corresponding dependencies for this artifact to function as a Config server while spring-cloud-starter-eureka brings Eureka client dependencies for the Config server to register with a Discovery server. spring-boot-maven-plugin allows to package the application as a jar or war file and to run it from command line using Maven as shown here.
ConfigServerApplication.java
, the entry point of this application looks like:
and EurekaClientConfiguration.java
:
Splitting the configuration in two classes is needed because the same Config server artifact could be used as a standalone service or as a service that registers with Eureka. No Eureka-related bean will be auto-configured if the registration-first Spring profile is not used.
@EnableConfigServer allows this application to run as a Config server aided by Spring Boot’s auto-configuration capabilities. @SpringBootApplication and SpringBootServletInitializer have been already explained in Developing Microservices using Spring Boot, Jersey, Swagger and Docker while @EnableDiscoveryClient was reviewed in Service Registration and Discovery using Spring Cloud Eureka.
The last relevant piece of the Spring Cloud Config server would be its configuration properties:
application.yml
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
spring:
cloud:
config:
server:
git :
uri: https://bitbucket.org/asimio/demo-config-properties
---
spring:
profiles: registration-first
eureka:
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8000/eureka/
instance:
hostname: ${hostName}
statusPageUrlPath: ${management.context-path}/info
healthCheckUrlPath: ${management.context-path}/health
preferIpAddress: true
metadataMap:
instanceId: ${spring.application.name}:${server.port}
spring.cloud.config.server.git.uri property points to the Git repo backing the Spring Cloud Config server where files with properties would be stored. When using the registration-first Spring profile, the Config server will register with a Eureka server located at eureka.client.serviceUrl.defaultZone’s value.
If the Git repo is private, its credentials would to be passed using spring.cloud.config.server.git.username and spring.cloud.config.server.git.password properties.
5. CREATE THE DEMO CONFIG CLIENT
Similarly to Create the Config server, this command will create a Maven project in a folder named demo-config-client
and alternatively, it can also be generated using Spring Initializr tool then selecting Actuator, Config Client, Eureka Discovery and Web dependencies as shown below:
Spring Initializr - Generate Config Client
Demo Config client’s pom.xml
is similar to Config server’s except it includes spring-cloud-starter-config to connect to the Config server and spring-boot-starter-web to implement an API and provide actuator endpoints instead of spring-cloud-config-server:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
<properties>
...
<start-class>com.asimio.api.demo.main.Application</start-class>
...
</properties>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
...
Application.java
, the entry point of the Demo Config client looks like:
Basically autoconfigures the application beans, enables service registration with the Discovery server and scans components in com.asimio.api.demo.rest
package, where the resource implementation is found.
ActorResource.java
, the class implementing a simple endpoint:
This class implements /actors/{id}
which sends back a response with the msg value coming from a Git file fronted by the Config server. @RefreshScope is used in conjunction with the refresh actuator endpoint to reload the msg value once it gets updated in the Git repo.
Relevant Demo Config client configuration files look like:
bootstrap.yml
:
This application can be run using four Spring profiles, known-config-server, where the location of the Config server is known or registered-config-server, where the Config server metadata is first retrieved via the Discovery server and the other two profiles are development and production.
and application.yml
:
For security reasons, actuator endpoints are disabled, so it requires manually enabling the ones needed. In this case /refresh
endpoint is used to reload the msg value.
This application also registers with the Eureka server regardless of how the Eureka server metadata is found out.
6. GIT REPO PROPERTIES FILES
The Git repo backing the Config service properties is available at https://bitbucket.org/asimio/demo-config-properties/src which includes these files:
demo-config-client-development.properties:
demo-config-client-known-config-server.properties:
demo-config-client-production.properties:
7. RUNNING THE CONFIG SERVER IN CONFIG-FIRST MODE
These Maven commands could be used to start the Spring Cloud Config server:
Or building the Maven artifact and run it using Java:
Or even running it in a Docker container since Asimio’s Config server is publicly hosted in the Docker Hub at https://hub.docker.com/r/asimio/config-server:
7.1. READING APPLICATION CONFIGURATION PROPERTIES
The Config server could be queried using these formats:
/{application}/{profile}[/{label}] |
/{application}-{profile}.yml |
/{label}/{application}-{profile}.yml |
/{application}-{profile}.properties |
/{label}/{application}-{profile}.properties |
For instance:
8. RUNNING THE EUREKA SERVER
Since the Demo Config client and the Config server (when running in registration-first approach) will register with the Eureka service, lets start one instance first.
The Eureka server source code could be downloaded from here and run as:
9. RUNNING THE CONFIG CLIENT IN CONFIG-FIRST MODE
Please refer to Running the Eureka server for the commands included in this section to work properly.
Sending a request to /actors{id}
endpoint:
The output includes App message from development profile which is a property value coming from demo-config-client-development.properties.
The Demo Config client also registers with a Eureka service located at http://localhost:8001/eureka/
, value coming from demo-config-client-known-config-server.properties when using the known-config-server and depicted next:
Demo Config client registration in config-first approach
10. RUNNING THE CONFIG SERVER IN REGISTRATION-FIRST MODE
Please refer to Running the Eureka server for the commands included in this section to work properly.
Using spring-boot-maven-plugin plugin to start the Spring Cloud Config server:
Or starting the resulting artifact using Java:
Or starting multiple containers of asimio/config-server Config server Docker image available at https://hub.docker.com/r/asimio/config-server:
10.1. READING APPLICATION CONFIGURATION PROPERTIES
Once again, demo-config-client application properties for development Spring profile are reachable through:
And the Config server is also registered with the Eureka service.
11. RUNNING THE CONFIG CLIENT IN REGISTRATION-FIRST MODE
Please refer to Running the Eureka server for the commands included in this section to work properly.
Sending a request to /actors{id}
endpoint:
In this case, both, the Config server and Demo Config client service are registered with a Eureka instance at http://localhost:8001/eureka/
as shown next:
Config server and Demo Config client registration in registration-first approach
12. DYNAMIC CONFIGURATION
What happens if a properties file located in the Git repository is changed? Lets say demo-config-client-production.properties
is updated to:
In order for the Demo Config client application to reflect this change, someone would have to send a POST request to /refresh
actuator endpoint to the client application. Support for this behavior was added in ActorResource by adding the @RefreshScope annotation and enabling /refresh
endpoint.
Start the Discovery server:
Start the Config server:
Start the Demo Config client:
Send request to /actors/{id}
endpoint:
Update property in Git repo:
Reload the properties values in the client application:
Send another request to /actors/{id}
endpoint:
You can new see the new property value has been updated without the need to restart the Demo Config client application.
But wouldn’t it be nice if the changes are automatically reloaded without the need of hitting /refresh
? Stay tuned, I’ll cover Refreshable Configuration using Spring Cloud Config Server, Spring Cloud Bus, RabbitMQ and Git.
Thanks for reading and as always, feedback is very much appreciated. If you found this post helpful and would like to receive updates when content like this gets published, sign up to the newsletter.
13. SOURCE CODE
Accompanying source code for this blog post can be found at: