After reading so many blogs, books about microservices we think like yes it's easy what's new in microservices it's just writing separate services based on Domain-Driven Design (DDD) subdomains. But in practice it comes up with some challenges and what are those challenges? How we can resolve them ? How actual microservice development works? What steps need to take in the initial phase to start with microservice development? How is it works in production? etc All these questions excited me to start writing this project.
- Service Registration & Discovery Microservice using spring cloud eureka-server
- Central Config Service from where we can fetch/update configured value at runtime
- Individual Microservices and how they register itself at Discovery/Registration Microservice and fetch the configured values from config service
- How to call one microservice form another microservice using FeignClient/RestTemplate
- Hystrix Circuit Breaker
- API Gateway
- Microservice Health checks API using Spring Boot Actuator Application metrics
- Microservice Application Metrics
- Authentication Server and Resource Server with OAuth2
- How to Secure microservices
- How to call microservices with oauth token
- How to Dockerize microservices
- How Dockerized individual microservice communicate between each other
The simple plain HRMS application will be having following functionalities
- HR will be able to create/update/delete the organization
- HR will be able to create/update/delete an employee under the organization
- HR will be able to allocate the leaves to an organization
- HR will be able to allocate the leaves to an employee
- Employee can apply/cancel leaves based on allocated leaves
Based on role an employee (TL,Manger) can approve/reject the leaves of an employees those are under his/her[TODO]
This HRMS application demonstrates how to build an application using microservices architecture paradigm with Polyglot Languages (Java), frameworks like Spring Boot & Polyglot Persistence software (Postgres). The application includes following functional microservices & infrastructure microservices. All of these microservices are independently deployable applications and are organized around business capabilities.
- Organization Microservice
- Employee Microservice
- Leave Microservice
- Authentication Microservice
- Global Configuration Microservice
- Service Registration & Discovery Microservice
- API Gateway Microservice
- JDK 8 - Install JDK 1.8 version from here
- Maven - Download latest version of Maven from here
- PostgreSQL - Download and install PostgreSQL from here
- IntelliJ IDEA Community Edition [Optional] - Install IntelliJ IDEA Community Edition from here
- Docker [Optional] Install Docker from here
Clone repository source code by executing following instruction to any folder on your machine,
https://github.com/nikhilshinde57/hrms-spring-boot-microservices-implementation.git
cd hrms-spring-boot-microservices-implementation
Setup postgres database on local machine and apply script db-setup-script.sql script located at this path src/main/resources/sql-scripts/db-setup-script.sql
Maven has been used as a build tool to build Spring Boot based Microservices applications. To run a single microservice independently, use the following command on your terminal/console window in separate window for each service.
cd eureka-service
mvn clean install
mvn spring-boot:run -Dspring.profiles.active=local
cd config-server
mvn clean install
mvn spring-boot:run -Dspring.profiles.active=local
cd oauth2-authentication-service
mvn clean install
mvn spring-boot:run -Dspring-boot.run.profiles=local
cd organization-service
mvn clean install
mvn spring-boot:run -Dspring-boot.run.profiles=local
cd employee-service
mvn clean install
mvn spring-boot:run -Dspring-boot.run.profiles=local
cd leave-service
mvn clean install
mvn spring-boot:run -Dspring-boot.run.profiles=local
cd gateway-service
mvn clean install
mvn spring-boot:run -Dspring.profiles.active=local
Here you can check all services are up or not and they are registered or not.
Here you can check all the available routes.
// 20200512201118
// http://localhost:8762/routes
{
"/leave-service/**": "leave-service",
"/employee-service/**": "employee-service",
"/config-service/**": "config-service",
"/organization-service/**": "organization-service"
}
Now using above Gateway Service routes we can now call the other services like
To get all employess we use: http://localhost:8762/employee-service/api/employees
To get all organizations we use: http://localhost:8762/organization-service/api/organizations
- Organization Service Health Check
- Employee Service Health Check
- Leave Service Health Check
- Authentication Service Health Check
- Config Service Health Check
- Organization Service Metrics
- Employee Service Metrics
- Leave Service Metrics
- Authentication Service Metrics
- Config Service Metrics
Maven has been used as a build tool to build Spring Boot based Microservices applications.
mvn clean install
This command might take a while for first time as it needs to download serveral dependency libraries from Maven repository. This command will build & package all microservice applications.
To run the docker containers make sure that you have installed and running docker on your machine by running below command on your machine's terminal window.
> docker --version
Docker version 19.03.8, build afacb8b
Upon successful building of microservices, you can now build Docker images and run containers Docker host on your machine. Note: If on your local machine you are running Postgres on port 5432 then stop that service before running below command.
Issue following command under the docker-compose directory, to run Docker containers,
docker-compose up
Above command starts all Microservices Docker containers as specified in 'docker-compose.yml' file. It will take some time to create and pull all the images and to run the containers.
Service Discovery Microservice: Here you can check all services are up or not and they are registered or not.
The rest of all the services are exposed on the same port as mentioned earlier.
When the all services are up you can signup up into the system using Authentication service. Here we have used the Oauth2 in that we implemented our own Authentication Server. The all our microservices are treated as a resources and we need to authenticate and authorize a user when he wants to access our resource. At the time of starting of an Authentication microservice we have added/registered the client to our authentication server. There are three main roles using that use can SingUp. Those roles are: [ADMIN,TL,USER]
USER CAN:
Resource: Organizations
Operations: GetHisOrganizationInformation
Resource: Employee
Operations: Search/UpdateHisOwnInformation
Resource: Employee Leave allocation
Operations: NONE
Resource: Organization Leave allocation
Operations: NONE
Resource: Employee Leave application
Operations: Apply/UpdateHisOwnLeaveApplication
TL CAN:
Resource: Organizations
Operations: Same as USER can do
Resource: Employee
Operations: Same as USER can do
Resource: Employee Leave allocation
Operations:NONE
Resource: Organization Leave allocation
Operations: NONE
Resource: Employee Leave application
Operations: Same as USER can do + GetTeamMembersLeaveApplications
ADMIN CAN:
Resource: Organizations
Operations: Same as TL can do + Create/Update/Delete/GetAll
Resource: Employee
Operations: Same as TL can do + Create/Update/Delete/GetAll
Resource: Employee Leave allocation
Operations: Allocate/Update/Delete/GetAll
Resource: Organization Leave allocation
Operations: Allocate/Update/Delete/GetAll
Resource: Employee Leave application
Operations: Same as TL can do + Apply/Update/Get/GetAll
Here client means the one who want to access/call our resources/microservice like it can be any webui application, mobile app or even postman from where we are accessing/calling the resource. The registered client details you can find it in client_details table of authentication service DB. Client details:
client_id:hrms
client_secret:yDx01x2YfQ
authorized_grant_types:password
scope:webclient
The user can SignUp by making below request.
POST /oauth/signup HTTP/1.1
Host: localhost:8060
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 75389844-7db3-b93f-be1a-fb85883cec45
{
"username":"nikhil",
"email":"niikhilshinde57@gmail.com",
"password":"password1",
"role":["admin"]
}
{
"message": "User registered successfully!"
}
To get the token user need to send the client details like client_id and secret in Authorization and in request body he need to send grant_type,scope, username, password. As mentioned earlier the registered client is having values like client_id:hrms and client_secret:yDx01x2YfQ. The all postman request call file and screenshots of token retrieval process you can find it in /postman_request_file_and_screenshots folder.
POST /oauth/token HTTP/1.1
Host: localhost:8060
Authorization: Basic {base64_encode(hrms:yDx01x2YfQ)}
Cache-Control: no-cache
Postman-Token: 0511ef73-1012-2709-3b96-753c5983c585
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="grant_type"
password
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="scope"
webclient
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="username"
nikhil
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="password"
password1
------WebKitFormBoundary7MA4YWxkTrZu0gW--
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTMzNjc0MjAsInVzZXJfbmFtZSI6Im5pa2hpbCIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiOTA0Yjg5YTItYTRjYy00NTg5LTk0ODUtNmFlZmYzZmFjOTM2IiwiY2xpZW50X2lkIjoiaHJtcyIsInNjb3BlIjpbIndlYmNsaWVudCJdfQ.xjzOFQRik4R-PoKxwfw5xrHu-dEouGOqNm9Zcjpy5PA",
"token_type": "bearer",
"expires_in": 899,
"scope": "webclient",
"jti": "904b89a2-a4cc-4589-9485-6aeff3fac936"
}
GET /oauth/user HTTP/1.1
Host: localhost:8060
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTMzNjc0MjAsInVzZXJfbmFtZSI6Im5pa2hpbCIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiOTA0Yjg5YTItYTRjYy00NTg5LTk0ODUtNmFlZmYzZmFjOTM2IiwiY2xpZW50X2lkIjoiaHJtcyIsInNjb3BlIjpbIndlYmNsaWVudCJdfQ.xjzOFQRik4R-PoKxwfw5xrHu-dEouGOqNm9Zcjpy5PA
Cache-Control: no-cache
Postman-Token: 560b822e-5b5f-a2e1-9f14-d5c6e79b0738
{
"clientId": "hrms",
"scope": [
"webclient"
],
"user": "nikhil",
"authorities": [
"ROLE_ADMIN"
]
}
Now using above received token we can access the resources(microservices) by sending that token in header.
GET /employee-service/api/employees/ HTTP/1.1
Host: localhost:8762
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTMzNjc0MjAsInVzZXJfbmFtZSI6Im5pa2hpbCIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiOTA0Yjg5YTItYTRjYy00NTg5LTk0ODUtNmFlZmYzZmFjOTM2IiwiY2xpZW50X2lkIjoiaHJtcyIsInNjb3BlIjpbIndlYmNsaWVudCJdfQ.xjzOFQRik4R-PoKxwfw5xrHu-dEouGOqNm9Zcjpy5PA
Cache-Control: no-cache
Postman-Token: 695cc1e3-3357-e607-df66-7a98c8f627b2
GET /organization-service/api/organizations/ HTTP/1.1
Host: localhost:8762
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTMzNjc0MjAsInVzZXJfbmFtZSI6Im5pa2hpbCIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiOTA0Yjg5YTItYTRjYy00NTg5LTk0ODUtNmFlZmYzZmFjOTM2IiwiY2xpZW50X2lkIjoiaHJtcyIsInNjb3BlIjpbIndlYmNsaWVudCJdfQ.xjzOFQRik4R-PoKxwfw5xrHu-dEouGOqNm9Zcjpy5PA
Cache-Control: no-cache
Postman-Token: d320293c-7ce5-f86d-16c6-f2dce7a5f1f1
GET /leave-service/api/leave-allocation/organizations HTTP/1.1
Host: localhost:8762
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTMzNjc0MjAsInVzZXJfbmFtZSI6Im5pa2hpbCIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiOTA0Yjg5YTItYTRjYy00NTg5LTk0ODUtNmFlZmYzZmFjOTM2IiwiY2xpZW50X2lkIjoiaHJtcyIsInNjb3BlIjpbIndlYmNsaWVudCJdfQ.xjzOFQRik4R-PoKxwfw5xrHu-dEouGOqNm9Zcjpy5PA
Cache-Control: no-cache
Postman-Token: 4b1d748a-b00e-7932-ceb7-c7fcc1b93e06
Note: Above API endpoints are the API Gateway endpoint's you can make a call to individual service like shown below:
GET /api/organizations/1 HTTP/1.1
Host: localhost:8030
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTMzNjc0MjAsInVzZXJfbmFtZSI6Im5pa2hpbCIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiOTA0Yjg5YTItYTRjYy00NTg5LTk0ODUtNmFlZmYzZmFjOTM2IiwiY2xpZW50X2lkIjoiaHJtcyIsInNjb3BlIjpbIndlYmNsaWVudCJdfQ.xjzOFQRik4R-PoKxwfw5xrHu-dEouGOqNm9Zcjpy5PA
Cache-Control: no-cache
Postman-Token: ac87917f-ab3f-8ae4-4011-7f3a89f56a80