Welcome back, glad to have you here again.

This post is part of the series ‘Microservices with Mo’. Just hit the links if you want to follow along:

Part 0: Intro

Part 1: Setting up docker

Part 2: The architecture

Part 3: The Counter Microservice

Today we are going to introduce a configuration service which will be the centralized source of configurations for our microservices.

What is a config server and why do we need it?

Think I need to play the role of a salesman for a bit:

Imagine you have a lot of microservices running — think about 10 / 50 / 200 … you get the point. Would it not be awesome to have a centralized place where you could manage the configuration of all of them? For each and every instance of whatever microservice?

Another scenario: You or another developer are changing the configurations of a few services. After two weeks you realize that mistakes have been made and you need the knowledge of what the working configurations were. Wouldn’t it be nice to have a version control system for your configurations?

Look no further this is what a configuration service is able to do.

For our simple use-case here it might be overkill but like we said this is all about the environment around our microservices.

Where should we start?

At first I want to create something inside the microservice we implemented in the previous part of the series. At the moment it does not use any configuration and therefore a configuration service could be kind of pointless right?

Therefore we will modify our CounterController a bit like in the following code snippet:

@RestController

public class CounterController {



private AtomicLong count = new AtomicLong(0L);



@Value(value = "${counter.prefixMessage}")

private String prefixMessage;



@GetMapping(path = "/count")

public String getCount(){

return prefixMessage + count.getAndIncrement();

}

}

Here we introduced a prefixMessage which will be printed before the actual count we are returning. In consequence the return type of our Controller-Method has changed to String.

Also we added the key to our application.properties :

counter.prefixMessage=Hello World:

If we now access the count-Endpoint of our freshly started microservice we get greeted with an Hello World: 0 .

Off to the config service:

Let’s get started with the config service.

Like before our journey will begin at http://start.spring.io/.

There we should update the group- and artifactID again (I have chosen com.marcuseisele.springboot_microservices and configservice). As dependencies I only added Config Server .

After downloading the zip and extracting it to our repository I quickly brought the repository itself up to date:

Copy the Dockerfile to the configservice folder and update it with the proper jar name: configservice-0.0.1-SNAPSHOT.jar Update the docker-compose.yml Add the config service to the pom.xml inside the repository root

Implementing the config service:

After we have copied there are a few things still left to do in order to set up the service properly. At fist we need to add @EnableConfigServer to some Configuration-Class or simply the main-class. For the sake of simplicity I added it to main-class. By doing that we enable the functionality of the configuration service. Still we are missing some pieces.

@SpringBootApplication

@EnableConfigServer

public class ConfigserviceApplication {



public static void main(String[] args) {

SpringApplication.run(ConfigserviceApplication.class, args);

}

}

The config service has not yet a place were we could store our configuration and it runs locally on the default port 8080. The latter is not really a problem since we run the services containerized and just could update the port forwarding inside the docker-compose.yml . For testing the services locally I would love to have a profile which uses a specific port so that I can run it with other services side-by-side. Because of that I created an application-local.properties file which will set the properties needed for running locally. Besides setting the server port to 8888 I also wanted to use a local repository as source of my configuration files.

server.port=8888

spring.cloud.config.server.git.uri=${HOME}/git/microservice-config

Now we need to make sure that the folder specified here is pointing to a git repository which should keep track of all configuration files. For the sake of simplicity I will let you guys just put the public repository in there which I created for this tutorial.

The URL is https://github.com/eiselems/microservice-config.

If you are adding your own repo here you need to create a property file similiar to https://raw.githubusercontent.com/eiselems/microservice-config/master/counterservice.properties inside the root of your configuration repository.

After setting everything up we now can start it locally via: ./mvnw springboot:run .

In order to test the proper content of our config server we can access the provided config of our config server at http://localhost:8888/counterservice/default and should be greeted by something similiar to this:

{

"name":"counterservice",

"profiles":[

"default"

],

"label":null,

"version":"d5d4a8051a8c2f37a3c43282c156aba06162992c",

"state":null,

"propertySources":[

{

"name":"/Users/marcuseisele/git/microservice-config/counterservice.properties",

"source":{

"counter.prefixMessage":"Hello EVERYBODY: "

}

}

]

}

Updating the counter service:

In order to leverage the potential of the config service we need to update the counter service. After having it done myself I realized it is easier than I expected.

Just add following dependency to the pom.xml of the counterservice.

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-config</artifactId>

</dependency>

With the following dependency management:

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-config</artifactId>

<version>1.3.2.RELEASE</version>

<type>pom</type>

<scope>import</scope>

</dependency>

</dependencies>

</dependencyManagement>

With these settings the counter-service will by default look for a configuration service at localhost:8888 which just matches our needs here.

Now we will update the applications.properties to update some properties so that it looks like this:

spring.application.name=counterservice

counter.prefixMessage=Hello World:

management.security.enabled=false

We added the application name by which the application will lookup its properties at the configuration service. The last line is for enabling the possibility to reload the configuration on the fly via an actuator endpoint. By default this endpoint is basic auth protected — we just disabled that for the sake of our tutorial.

After that we will add a @RefreshScope on top of our @Countercontroller . Which enables reloading of the configurations from the config server by sending a POST-Request to the /reload endpoint of the counterservice.

If we now start the configservice and the counterservice and hit the count endpoint on http://localhost:8080/count we will get greeted by the message “Hello EVERYBODY: 0”. As you see this is the message provided by the configserver.

Earlier I wrote something about a reload feature. We already added it by adding the RefreshScope-Annotation. We can test it by (while running both services) switching to our config repository and modifying the counterservice.properties there. After adding the modification we need to commit that change. Now that we updated the source of the config we can verify it again on: http://localhost:8888/counterservice/default. Here we should now see the new values for the message. Now we need to grab a REST Client or simply use cURL to do a POST to the http://localhost:8080/refresh endpoint.

After that we can see that the count Endpoint of our counterservice at http://localhost:8080/count returns the new values from the configservice.

Great so far …

We are now able to reload or configuration which is some sort of pull-mechanic. If we think about scaling our services it still would be difficult to update a lot of configurations at once since we would have to hit the refresh-endpoint for every service which should be updated.

Spring Cloud also offers a solution for just this: Spring Cloud Bus.

Spring Cloud Bus is according to their page: “Linking nodes of a distributed system with a lightweight message broker”. It can easily be used for updating the configurations. The only downside is that it relies on a message broker and therefore we would have to update our docker setup to provide one.

Since I don’t want to drag this article too much I will add this in a future addition to the series. In case you have the urge to want to know more about the automatic update mechanism — just let me know! In that case I will probably update it sooner than later.

When writing this paragraph I realized that I initially wanted to create the Service Discovery in advance to the Configuration Service. So I guess creating the Service Disovery will be the next part of the series 😄

Again you can review all changes made during this part on GitHub (Link to diff view / Link to branch after finishing this part)

As always I hope you like this part and the series in total. Feel free to ask anything that is questioning you or parts where you think I could improve something. I already learned a lot by the feedback I received. Nobody is perfect and so am I.

Link to next story: Part 5 the Service Registry