Saturday, June 24, 2017

Microservice:Spring Cloud Config Server Step by Step

Config Server for Microservices


In Microservices we create central config server where all configurable properties of micro-services reside and it is version controlled, benefit of central config server is if we change a property for a microservice it can reflect on the fly without redeploying the Microservice.
Before Microservices we create a properties files where we maintain our configurable property so if we change the property value or add or delete a property  we generally need to restart the application container moreover think about the environments often we have development, Staging and Prod environment and each has separate Url for different services like JMS, JNDI etc. so also if environment changes we need to pick right properties file like for development we need to load development property file. Spring provides the Profile concept where based on profile pass Spring load appropriate environments property
Like if profile value is dev it loads all {}-dev.properties.
But the main problem is it is tied to the codebase or statically packaged so any changes in properties file need to build and redeployed the application which is violation of Microservice principle  where it clearly stated
build just once and deploy it any environment.


So somehow we need a technology which maintains all properties and if any properties are changed it will pick up the changes and reflect the same without application rebuild or restart.
The answer is Spring Cloud config server.

Spring Cloud config server Architecture

Few important components of config server .

Repository area : Config server stores all Microservices property files in a Version control system so it can be version controlled and this version control system can be git or svn, but most popular are GIT.Also, you can store it in filesystem then your profile should be native.Config server stores each micro-service properties based on the Service ID. we can configure Microservice Service Id by giving a unique value of spring.application.name property in bootstrap.properties file for that Microservice.
Say I have an Employee Payroll Microservice then I can create a ServiceID like following
In Employee Payroll bootstrap.property file.

spring.application.name=EmployeePayroll.

Now in Config server, we have a set of property files for Employee payroll based on environment
like
EmployeePayroll-dev.properties
EmployeePayroll-stg.properties
EmployeePayroll-prod.properties
Based on profile value.

Note that properties file name should be in the following format.

{ServiceID}-{profile}.properties.

If we do not give the profile name in property file then it is considered as default


Here EmployeePayroll-dev is Service ID and dev/stg/prod are environments.



REST Endpoint : Now every microservices need to communicate with Config server so it can resolve the property value, as all property is stored in Config server. Config server publishes rest endpoint through that microservices communicate with them or we can see the properties in the browser.

Actuator :  If any properties for a microservice has been changed that has been refreshed through Actuator refresh rest endpoint. By doing this Microservice got updated property without rebuild the application.


Cloud Bus : This is optional but very useful. think if we need to refresh actuator endpoint manually for each service then it will be a hectic task as a complex business domain has many microservices. In this scenario, cloud bus helps to push the updated properties to all its subscribed Microservices but for trigger this action we need to manually refresh one Microservice endpoint.
I will talk letter about cloud bus.

Load Balancer :  As all the configurable properties are stored in Config server so it is necessary to up before all Microservices started as all Microservices instance querying the config server to resolve it properties when bootstrapped. So Config server should be Highly Available so if we maintain only one Config server Box/Container it can be a Single point of failure Ideally it should be load balanced so that we can run multiple instances of config servers and load balancer pool should have one public address where every microservice communicated. I also talk about Load Balancer in another article elaborately.

Config server Architecture Diagram (Without load balancing and Cloud bus.






Now we will create a config server using Spring Cloud


  1. Setting up File Sytem:


Here I will setup a native  Filesystem based config server  I am not using git. So I will create a local file structure but in production environment please create a git remote repository. To set up a local filesystem execute the following commands in Linux environment (same for windows just need to create file using GUI.)



  1. mkdir CentralRepo
  2. cd CentralRepo
  3. touch config.properties
  4. vi config.properties
  5. Hit insert
  6. Write welcome.message=Hello Spring Cloud
  7. Hit esc and wq!



2. Coding for Config server:

Implement config server we will use Spring cloud Netflix config server distribution.


Create a template project using dependencies Actuator and Config server

Page will look like following


Now  hit the Generate Project button so it will download the code template.

After that I extract the code template and then import the project as an Maven project into eclipse.



If you open the pom.xml it will look like following

<?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>MicroserviceCongigServer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>MicroserviceCongigServer</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.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>
        <spring-cloud.version>Dalston.SR1</spring-cloud.version>
    </properties>

    <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.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <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>

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


</project>



Now open the MicroserviceCongigServerApplication.java under com.example.MicroserviceCongigServer package.

Put @EnableConfigServer annotation on top of the class by doing so we tell SPring boot app to treat it as Config server module.

MicroserviceCongigServerApplication.java

package com.example.MicroserviceCongigServer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableConfigServer
public class MicroserviceCongigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceCongigServerApplication.class, args);
    }
}



Now rename the application properties to bootstrap.properties and put the following lines

server.port=9090
spring.cloud.config.server.native.searchLocations=file://${user.home}/CentralRepo/
SPRING_PROFILES_ACTIVE=native

So the config server runs on 9090 port and we put the native file system location so config server gets the properties files from file system rather than git we also tell config server that this is a native profile.


At this point, we are all set to  run the MicroserviceCongigServerApplication.java and it will up the config server


and we can see following response


{"name":"config","profiles":["default"],"label":null,"version":null,"state":null,"propertySources":[{"name":"file:///home/shamik/centralRepo/config.properties","source":{"welcome.message":"Hello Spring Cloud"}}]}