Blog Back to all posts View all authors

Share app's configuration with Consul

Recently I have come across a rather interesting tool - the Consul. It can serve as Service Discovery, check whether these services are responding to requests and even provide them with a key-value store.

The last functionality has caught my eye in particular. Why? You will find out soon!

 

Every application needs a configuration. We can pass variables directly on the command line, read from a file (we usually do that), and sometimes (sometimes quite often but shhh!) - hard-coded in the code, which generates additional time costs (time.equals(money)) at the support stage. It can be very convenient to keep all configuration data in one place so that your infrastructure applications receive data from there.

 

It might seem that the configuration file is a great solution. Haha, wrong answer!


Example time! One of our clients wants to be able to dynamically change some values in configs. The application is written using Spring Boot and uses the application.properties (with a bunch of profiles) as the configuration file. Normally, you need to restart the server and make some changes in the configuration. However, there are cases when due to a typo or a minimal change, it is necessary to re-compile, build and deploy the application, which can be very time-consuming. Or even inadmissible. The situation is impaired in the case of distributed systems. Here the Consul will help us!

 

Take a look at the work of the Consul on the example of the simplest Spring Boot application mentioned before.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>consul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>consul</name>
    <description>Demo project for Spring Boot with Consul</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
</build>

</project>

In the configuration file, create a variable which has a value that is going to be returned (I hope your application does more meaningful things).

application.yml


foo: bar

com.example.consul.ConsulApplication.java


package com.example.consul;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class ConsulApplication {

   @Value("${foo}")
   private String foo;
   public static void main(String[] args) {
      SpringApplication.run(ConsulApplication.class, args);
   }
   @GetMapping("/foo")
   public String getFoo() {
      return foo;
   }
}

Run the application:


mvn spring-boot:run

and open the following endpoint in your favourite browser

http://localhost:8080/foo

In the answer, you should get "bar" (at least I hope for it ).

 

spring boot consul, spring boot consul config, spring cloud config, spring boot consul key value example, spring cloud consul example - servocode.com

So, what if your client (or you) is fed up (changed requirements etc.) with the return value? Or the value often changes, but it is impossible to constantly compile and run the application or reluctantly? There is one golden solution. You add the Consul in advance!

Add support for the Consul in thr application.

pom.xml


<dependency>

    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-all</artifactId>
    <version>1.3.0.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
    <version>1.3.0.RELEASE</version>
</dependency>

Next to application.yml, create bootstrap.yml, which is loaded before the previous one.spring:


  application:
    name: ConsulDemo
  cloud:
    consul:
      host: localhost
      port: 8500
      config:
        enabled: true


Restart the app:


mvn spring-boot:run

It is time to start the Consul. To do this, use the ready docker image. Yes, you need to have a Docker installed. Here is the link if you haven't done it yet: https://www.consul.io/downloads.html.


docker run -d --rm --name consul -p 8500:8500 consul

By default, Consul runs on port 8500, but in the products, most likely, you want to change both the address and the port. While opening in the browser http://localhost:8500 we will see a fairly simple and nice interface, as well as our connected application.

 

spring boot consul, spring boot consul config, spring cloud config, spring boot consul key value example, spring cloud consul example - servocode.com

Consul looks for the value of the variables in "/config/${appName}". In our case, you need to create the "/config/ConsulDemo/foo" key with some new value, for example, "New value".

 

spring boot consul, spring boot consul config, spring cloud config, spring boot consul key value example, spring cloud consul example - servocode.com

Then restart the application once again and open http://localhost:8080/foo in the browser and we will see the new value.

 

spring boot consul, spring boot consul config, spring cloud config, spring boot consul key value example, spring cloud consul example - servocode.com

Now you can change the key value at any time and it will be automatically applied the next time it is called. But for this to work, you need to add an @RefreshScope annotation to our controller. After that, changing the values of variables works without restarting the application and SMS.

Project structure

 

spring boot consul, spring boot consul config, spring cloud config, spring boot consul key value example, spring cloud consul example - servocode.com

 

Of course, not all values can be applied without reloading (for example, the port on which the application will be launched), but you will agree: it is very pleasant to test various settings of the application or to lose the need to satisfy such whims of your clients without spending time compiling, assembling and deploying the application!

You can download the whole code here https://github.com/ServoCodeBlog/consul

SEE ALSO

The Simplest Introduction To Consul

contact us

Have an idea ? Let’s talk

Office in Rzeszow
Office in Warsaw
CONTACT US
CONTACT INFORMATION

GET IN TOUCH

Fill up the form and we will contact you shortly

Name
E-Mail
Message

Company information

Fill up the form and we will contact you shortly.

ServoCode Sp. z o.o.

Jasionka 954E, 36-002 Jasionka, Poland

NIP: 8133719852

REGON: 364182909

KRS: 0000611643

We are using cookies to provide statistics that help us give you the best experience of our site. You can find out more or switch them off if you prefer. However, by continuing to use the site without changing settings, you are agreeing to our use of cookies. Read more

close