visit
What will be used to build the system:
The complete code can be found here.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ser.hkrn</groupId>
<artifactId>microservice-package-hkrn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>microservice-package-hkrn</name>
<packaging>pom</packaging>
<description>microservice-package-hkrn</description>
<properties>
<java.version>17</java.version>
</properties>
<modules>
<module>discovery-service</module>
<module>business-service</module>
<module>gateway-service</module>
</modules>
</project>
<modules>
<module>discovery-service</module>
<module>business-service</module>
<module>gateway-service</module>
</modules>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<parent>
<groupId>ser.hkrn</groupId>
<artifactId>microservice-package-hkrn</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
spring.security.user.name=${eureka_login:login}
spring.security.user.password=${eureka_password:pass}
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
For Discovery Service use 8761
port:
server.port=8761
Then, create SecurityFilterChain
which is a bean to configure HTTP security:
@Configuration
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeHttpRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.and()
.formLogin();
return http.build();
}
Finally, put @EnableEurekaServer
annotation over the main class:
@EnableEurekaServer
@SpringBootApplication
public class DiscoveryServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryServiceApplication.class, args);
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<parent>
<groupId>ser.hkrn</groupId>
<artifactId>microservice-package-hkrn</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
spring.application.name=business-service
eureka.client.serviceUrl.defaultZone=//${eureka_login:login}:${eureka_password:pass}@${eureka_url:localhost}:${eureka_port:8761}/eureka/
server.port=${business_service_port:8081}
@Controller
public class VersionController {
@GetMapping("/resolve/version")
public ResponseEntity<?> resolveVersion() {
return ResponseEntity.ok(new Object() {
public String version = "0.0.1-SNAPSHOT";
});
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<parent>
<groupId>ser.hkrn</groupId>
<artifactId>microservice-package-hkrn</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
spring.application.name=gateway-service
eureka.client.serviceUrl.defaultZone=//${eureka.login:login}:${eureka.password:pass}@${eureka.url:localhost}:${eureka.port:8761}/eureka/
server.port=8082
it's important to create RestTemplate
bean:
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
Note the @LoadBalanced
annotation. It allows you to use the Eureka Server to balance the requests. Otherwise, requests will be sent to the given URL avoiding Eureka.
@Controller
public class BusinessController {
private final RestTemplate restTemplate;
public BusinessController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/business")
public ResponseEntity<?> getBusinessVersion() {
return ResponseEntity.ok(
restTemplate.getForObject("//business-service/resolve/version", Object.class)
);
}
}
Basically, the controller receives requests and redirects them to the Business Service. Note that the name of the service is used in the URL: //business-service/resolve/version
. Eureka proceeds with the name and changes it to the IP address. Thus for communicating, it is enough to know only the service’s name.
FROM openjdk
COPY ./target/service-discovery-0.0.1-SNAPSHOT.jar /usr/app/
WORKDIR /usr/app
EXPOSE 8761
ENTRYPOINT ["java", "-jar", "service-discovery-0.0.1-SNAPSHOT.jar"]
FROM openjdk
COPY ./target/business-service-0.0.1-SNAPSHOT.jar /usr/app/
WORKDIR /usr/app
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "business-service-0.0.1-SNAPSHOT.jar"]
FROM openjdk
COPY ./target/gateway-service-0.0.1-SNAPSHOT.jar /usr/app/
WORKDIR /usr/app
EXPOSE 8082
ENTRYPOINT ["java", "-jar", "gateway-service-0.0.1-SNAPSHOT.jar"]
version: '3.1'
services:
discovery-service:
build: ./discovery-service
restart: always
environment:
- eureka.login=${eureka_login}
- eureka.password=${eureka_password}
- server.port=${eureka_port}
ports:
- 8080:${eureka_port}
business-service:
build: ./business-service
restart: always
environment:
- eureka.login=${eureka_login}
- eureka.password=${eureka_password}
- eureka.url=${eureka_url}
- eureka.port=${eureka_port}
- server.port=${business_service_port}
ports:
- 8081:${business_service_port}
links:
- discovery-service:${eureka_url}
gateway-service:
build: ./gateway-service
restart: always
environment:
- eureka.login=${eureka_login}
- eureka.password=${eureka_password}
- eureka.url=${eureka_url}
- eureka.port=${eureka_port}
- server.port=${gateway_service_port}
ports:
- 8082:${gateway_service_port}
links:
- discovery-service:${eureka_url}
As can be seen from the script, it contains all the necessary configurations for each service, and particular values are used. Using the variables allows deploying the microservices pack to any environment. To provide particular values we will use .env
files. For the production environment, we will create an .env
file, and an .env-dev
file for a development stand.
eureka_login=admin
eureka_password=CjPjaM97TybVR9O
eureka_url=eureka
eureka_port=8080
business_service_port=8081
gateway_service_port=8082
eureka_login=user
eureka_password=123
eureka_url=eureka
eureka_port=8080
business_service_port=8081
gateway_service_port=8082
docker-compose up -d
.env
files for each stand