[Guide] Implementing Spring Cloud Config

Changing configurations on running services can be cumbersome, especially if the application doesn't have a way to be configured remotely. Spring Cloud Config provides a way to make this easier by introducing a Config Server from which clients fetch their configuration. The figure below illustrates how Spring Cloud Config works.

Spring Cloud Config illustration

  • The Git repository is used to store the configuration since Git is pretty good at tracking and storing changes.
  • The Config server keeps itself up to date with the Git repository, and serves HTTP requests with configurations for the clients.
  • The Config clients request the configuration from the config server, which sets the properties in the application.

Setting up your Git repository

The configuration is maintained in a Git repository. If you e.g. have an application called 'configclient' you can specify it as seen below (or on Github).

configuration:  
  projectName: configclient
server:  
  port: 8000
message:  
  greeting: Hello from the configuration

Setting up the server

With a working Git repository, we need a Config server project. The easies way is to create it from Spring Initializr with "Config Server".

To set up the server you must:

  • annotate the main application with @EnableConfigServer (e.g. in ConfigserverApplication.java)
  • add a bootstrap.yml (under resources)
  • add the Git repository uri in the key spring.cloud.config.server.git.uri
  • set the application name as follows: spring.application.name=config-service
  • (optionally) set server.port=8888

The resulting bootstrap.yml is shown below.

spring:  
  application:
    name: config-service
  cloud:
    config:
      server:
        git:
          uri: https://github.com/rpicloud/guide-cloud-config
server:  
  port: 8888

Start the server by running mvn spring-boot:run from within the folder.
You should now be able to see the server at http://localhost:8888/configclient/default
If you didn't change server.port it is running at 8080.

The config-server source code can be found here.

Setting up the client

The client can request the configuration while bootstrapping. In this way we will show how to pick a port for the config client web server remotely.

The config client also needs a project. The easiest way is, again, to create it from Spring Initializr with "Config Client" and for the sake of the demonstation also "Web" and "Actuator".

To set up the client you must:

  • add a bootstrap.yml (under resources)
  • add the application name as seen below
  • add the uri to the cloud config server as seen below
spring:  
  application:
    name: configclient
  cloud:
    config:
      uri: http://localhost:8888

The config-client source code can be found here.

Refreshing

The class below shows how you can use the 'Actuator' to update running clients with a new configuration. This is done in the class Greeter as seen below.

@RefreshScope
@Component
@RestController
public class Greeter {

    @Value("${message.greeting}")
    String greeting;

    @Value("${server.port}")
    int port;

    @Value("${configuration.projectName}")
    String projectName;

    @RequestMapping(value = "/", produces = "application/json")
    public List<String> index(){
        List<String> env = Arrays.asList(
                "message.greeting is: " + greeting,
                "server.port is: " + port,
                "configuration.projectName is: " + projectName
        );
        return env;
    }
}

Now you should see a page telling you what the configuration server returned to you when you visit http://localhost:8000/.

If you point the Git repository to your own repository you will notice that the config server immediately returns the same, but the config client will wait until it is told to do so. You can make a POST request on the endpoint '/refresh' to do so as below (or by using Postman):

$ curl -d{} http://localhost:8000/refresh

You have to do this manually on every client unless you use the Spring Cloud Bus as explained in "Build self-healing distributed systems with Spring Cloud".

Profiles

Profiles are useful when you have multiple environments for your application. When you have a development and a production environment you probably want different settings in each. An example of this can be found in the gateway-ui example as seen below. The profiles are separated with "---", and there is a default profile and a "development" profile. The difference in the development profile is that the server port is 8080 and that the Zuul urls are changed to localhost. In this way you can easily have different urls for production and development.

configuration:  
  projectName: gateway-ui
server:  
  port: 80
zuul:  
  routes:
    cats:
      url: http://cat-service:9000
      path: /cats/**
      stripPrefix: false
    dogs:
      url: http://dog-service:9001
      path: /dogs/**
      stripPrefix: false
---
spring:  
  profiles: development
server:  
  port: 8080
zuul:  
  routes:
    cats:
      url: http://localhost:9000
      path: /cats/**
      stripPrefix: false
    dogs:
      url: http://localhost:9001
      path: /dogs/**
      stripPrefix: false
debug: true  

To set the profile to "development" you can export the following value in your environment

export SPRING_PROFILES_ACTIVE=development  

If you always use this profile you can add it to your bashrc or zshrc. On Ubuntu this can be done by adding the line above to your bashrc. You can open the file by running nano ~/.bashrc. The next terminal you open will now automatically have the environment variable assigned.

Spring Cloud Config:
http://cloud.spring.io/spring-cloud-config/

Build self-healing distributed systems with Spring Cloud:
http://www.javaworld.com/article/2927920/cloud-computing/build-self-healing-distributed-systems-with-spring-cloud.html

Introduction to Spring Cloud by Josh Long:
https://www.youtube.com/watch?v=SFDYdslOvu8

A description of profiles which can be a help when working with both a local development environment and a production.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html