microservices architecture java: Config Server
In microservices we create a central spring cloud config server where all configurable parameters of micro-services are written 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 era we create a properties files where we maintain our configurable parameter so if we change the parameter value or add or delete a parameter 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 the passing profile 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
- 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.)
- mkdir CentralRepo
- cd CentralRepo
- touch config.properties
- vi config.properties
- Hit insert
- Write welcome.message=Hello Spring Cloud
- Hit esc and wq!
2. Coding for Config server:
Implement config server we will use Spring cloud Netflix config server distribution.
Go to https://start.spring.io/
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"}}]}
Post a Comment