Dynamic Configuration Management in Microservice Architecture with Spring Cloud
This article is about the dynamic configuration management in Microservice Architecture with Spring Cloud.
1. Introduction
Dynamic configuration is the ability to change the behavior and functionality of a distributed system without bringing it down. It lets the developers modify the configuration at runtime. It also helps to test functionality in a production-like environment without affecting the live users. This feature can also be used effectively for the A/B testing of a system.
2. Spring Cloud
Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, a control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state).
You can also check this tutorial in the following video:
Coordination of distributed systems leads to boilerplate patterns, and using Spring Cloud developers can quickly stand up services and applications that implement those patterns. They will work well in any distributed environment, including the developer’s own laptop, bare metal data centers, and managed platforms such as Cloud Foundry.
2.1 Spring Cloud Config
Spring Cloud Config provides server and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments. The concepts on both client and server map identically to the Spring Environment and PropertySource abstractions, so they fit very well with Spring applications but can be used with any application running in any language.
As an application moves through the deployment pipeline from dev to test and into production you can manage the configuration between those environments and be certain that applications have everything they need to run when they migrate. The default implementation of the server storage backend uses git so it easily supports labeled versions of configuration environments, as well as being accessible to a wide range of tooling for managing the content. It is easy to add alternative implementations and plug them in with the Spring configuration.
2.2 Features
Spring Cloud Config Server features:
- HTTP, resource-based API for external configuration (name-value pairs, or equivalent YAML content)
- Encrypt and decrypt property values (symmetric or asymmetric)
- Embeddable easily in a Spring Boot application using
@EnableConfigServer
Config Client features (for Spring applications):
- Bind to the Config Server and initialize Spring Environment with remote property sources
- Encrypt and decrypt property values (symmetric or asymmetric)
3. Spring Cloud Config Server
Spring Cloud Config Server provides an HTTP resource-based API for external configuration (name-value pairs or equivalent YAML content). The server is embeddable in a Spring Boot application, by using the @EnableConfigServer
annotation.
LocalConfigServer.java
@SpringBootApplication @EnableConfigServer public class LocalConfigServer { public static void main(String[] args) { Application.run(LocalConfigServer.class, args); } }
To start the spring cloud config server run mvn spring-boot:run
inside the spring-cloud-config-server folder. The server is a Spring Boot application, so you can run it from your IDE if you prefer to do so (the main class is ConfigServerApplication
). Spring Cloud Config Server pulls configuration for remote clients from various sources: git repository, JDBC compatible database, Subversion, Hashicorp Vault, Credhub and local filesystems.
4. Spring Cloud Config Client
To use the client features in an application, you can build it as a Spring Boot application that depends on spring-cloud-config-client. The most convenient way to add the dependency is with a Spring Boot starter org.springframework.cloud:spring-cloud-starter-config
. There is also a parent pom and BOM (spring-cloud-starter-parent
) for Maven users and a Spring IO version management properties file for Gradle and Spring CLI users.
Now you can create a standard Spring Boot application that will pick the external configuration from the default local config server. The default port for the server is 8888
. To modify the startup behavior, you can change the location of the config server by using bootstrap.properties
:
spring.cloud.config.uri: https://mylocalconfigserver.com
5. Dynamic Configuration with Spring Cloud Example
We will need a Config service to act as a sort of intermediary between our Spring application and a version-controlled repository of configuration files. We can use the Spring Cloud.s @EnableConfigServer
to start a config server. This is a regular Spring Boot application with one annotation added to enable the config server.
The below class is from configuration-service/src/main/java/com/example/configurationservice/ConfigurationServiceApplication.java
ConfigurationServiceApplication.java
package com.example.configurationservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @EnableConfigServer @SpringBootApplication public class ConfigurationServiceApplication { public static void main(String[] args) { SpringApplication.run(ConfigurationServiceApplication.class, args); } }
The Config Server needs to know which repository to manage. There are several choices here but start with a Git-based filesystem repository. You could as easily point the Config Server to a Github or GitLab repository. On the file system, create a new directory and run git init
in it. Then add a file called a-bootiful-client.properties
to the Git repository. Then run git commit
in it. Later, you will connect to the Config Server with a Spring Boot application whose spring.application.name
property identifies it as a-bootiful-client
to the Config Server. This is how the Config Server knows which set of configuration to send to a specific client. It also sends all the values from any file named application.properties
or application.yml
in the Git repository. Property keys in more specifically named files (such as a-bootiful-client.properties
) override those in application.properties
or application.yml
.
Add a simple property and value (message = Hello world
) to the newly created a-bootiful-client.properties
file and then git commit the change.
Specify the path to the Git repository by specifying the spring.cloud.config.server.git.uri
property in configuration-service/src/main/resources/application.properties
. You must also specify a different server.port
value to avoid port conflicts when you run both this server and another Spring Boot application on the same machine. The following listing (from configuration-service/src/main/resources/application.properties
) shows such an application.properties file:
server.port=8888 spring.cloud.config.server.git.uri=/Users/ziameraj16/study/JCG/dynamic-configuration
Now that we have set-up a Config Server, we need to set-up a new Spring Boot application that uses the Config Server to load its own configuration and that refreshes its configuration to reflect changes to the Config Server on-demand, without restarting the JVM.
To do so, add the org.springframework.cloud:spring-cloud-starter-config
dependency, to connect to the Config Server. Spring sees the configuration property files, as it would any property file loaded from application.properties
or application.yml
or any other PropertySource.
The properties to configure the Config Client must necessarily be read in before the rest of the application’s configuration is read from the Config Server, during the bootstrap phase. Specify the client’s spring.application.name
as a-bootiful-client
and the location of the Config Server (spring.cloud.config.uri
) in configuration-client/src/main/resources/bootstrap.properties
, where it will be loaded earlier than any other configuration. The following listing shows that file:
configuration-client/src/main/resources/bootstrap.properties
spring.application.name=a-bootiful-client spring.cloud.config.uri=http://localhost:8888
You also want to enable the /refresh
endpoint, to demonstrate dynamic configuration changes. The following listing (from configuration-client/src/main/resources/application.properties
) shows how to do so:
management.endpoints.web.exposure.include=*
The client can access any value in the Config Server by using the traditional mechanisms (such as @ConfigurationProperties
or @Value("${…}")
or through the Environment
abstraction). Now you need to create a Spring MVC REST controller that returns the resolved message
property’s value.
6. Testing
You can test the end-to-end result by starting the Config Service first and then, once it is running, starting the client. Visit the client app in the browser at http://localhost:8080/message
. There, you should see Hello world in the response.
7. Summary
In this article, we learned about the Dynamic Configuration. We discussed the advantages of dynamic configurations and how to implement this using Spring Cloud. We looked at the Spring Cloud Server and the Client configurations needed to achieve dynamic behavior.