MicroServices

https://dzone.com/articles/microservices-communication-zuul-api-gateway-1 The crux of the microservices pattern is to create an independent service which can be scaled and deployed independently.

Base components

kubernetes

Kubernetes has a number of features. It can be thought of as:

Kubernetes provides a container-centric management environment. It orchestrates computing, networking, and storage infrastructure on behalf of user workloads. This provides much of the simplicity of Platform as a Service (PaaS) with the flexibility of Infrastructure as a Service (IaaS), and enables portability across infrastructure providers.

The New Way is to deploy containers based on operating-system-level virtualization rather than hardware virtualization. These containers are isolated from each other and from the host: they have their own filesystems, they can’t see each others’ processes, and their computational resource usage can be bounded. They are easier to build than VMs, and because they are decoupled from the underlying infrastructure and from the host filesystem, they are portable across clouds and OS distributions.

Loosely coupled, distributed, elastic, liberated micro-services: Applications are broken into smaller, independent pieces and can be deployed and managed dynamically – not a monolithic stack running on one big single-purpose machine.

You can run Kubernetes almost anywhere, from your laptop to VMs on a cloud provider to a rack of bare metal servers A local-machine solution is an easy way to get started with Kubernetes. You can create and test Kubernetes clusters without worrying about consuming cloud resources and quotas.

Community Supported Tools

Install kubectl centos

   1 cat <<EOF > /etc/yum.repos.d/kubernetes.repo
   2 [kubernetes]
   3 name=Kubernetes
   4 baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
   5 enabled=1
   6 gpgcheck=1
   7 repo_gpgcheck=1
   8 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
   9 EOF
  10 yum install -y kubectl

Install kubectl binary using curl

   1 curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
   2 chmod +x ./kubectl
   3 sudo mv ./kubectl /usr/local/bin/kubectl

Spring cloud Netflix

As long as Spring Cloud Netflix and Eureka Core are on the classpath any Spring Boot application with @EnableEurekaClient will try to contact a Eureka server on http://localhost:8761 (the default value of eureka.client.serviceUrl.defaultZone):

Eureka server on http://eureka:8761. To run your own server use the spring-cloud-starter-netflix-eureka-server dependency and @EnableEurekaServer.

Need to add @EnableZuulProxy annotation to the Main class to make this project a Zuul proxy server.

Zuul is a JVM-based router and server-side load balancer from Netflix.

Eureka + Spring Cloud gateway

microservice chuck norris

Microservice capable of register itself in an eureka server that has default URL http://127.0.0.1:8761 . Has actuator endpoints for info and health. The HTTP port can be set using -Dserver.port=8082.

pom.xml

   1 <?xml version="1.0" encoding="UTF-8"?>
   2 <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">
   3     <modelVersion>4.0.0</modelVersion>
   4     <groupId>bitarus.allowed.org</groupId>
   5     <artifactId>chucknorris</artifactId>
   6     <version>0.1.0</version>
   7     <parent>
   8         <groupId>org.springframework.boot</groupId>
   9         <artifactId>spring-boot-starter-parent</artifactId>
  10         <version>2.6.7</version>
  11     </parent>
  12     <dependencies>
  13         <dependency>
  14             <groupId>org.springframework.boot</groupId>
  15             <artifactId>spring-boot-starter-actuator</artifactId>
  16         </dependency>
  17         <dependency>
  18             <groupId>org.springframework.boot</groupId>
  19             <artifactId>spring-boot-starter-thymeleaf</artifactId>
  20         </dependency>
  21         <dependency>
  22             <groupId>org.springframework.boot</groupId>
  23             <artifactId>spring-boot-starter-web</artifactId>
  24         </dependency>
  25         <dependency>
  26             <groupId>org.springframework.cloud</groupId>
  27             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  28             <version>3.1.2</version>
  29         </dependency>
  30         <dependency>
  31             <groupId>com.google.code.gson</groupId>
  32             <artifactId>gson</artifactId>
  33             <version>2.9.0</version>
  34             <scope>compile</scope>
  35         </dependency>
  36     </dependencies>
  37     <properties>
  38         <start-class>chucknorris.bitarus.allowed.org.Application</start-class>
  39     </properties>
  40     <build>
  41         <plugins>
  42             <plugin>
  43                 <groupId>org.springframework.boot</groupId>
  44                 <artifactId>spring-boot-maven-plugin</artifactId>
  45             </plugin>
  46         </plugins>
  47     </build>
  48     <repositories>
  49         <repository>
  50             <id>spring-milestone</id>
  51             <url>http://repo.spring.io/libs-release</url>
  52         </repository>
  53     </repositories>
  54     <pluginRepositories>
  55         <pluginRepository>
  56             <id>spring-milestone</id>
  57             <url>http://repo.spring.io/libs-release</url>
  58         </pluginRepository>
  59     </pluginRepositories>
  60 </project>

src/main/java/chucknorris/bitarus/allowed/org/Application.java

   1 package chucknorris.bitarus.allowed.org;
   2 
   3 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
   4 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
   5 import org.springframework.boot.SpringApplication;
   6 import org.springframework.context.annotation.ComponentScan;
   7 import org.slf4j.Logger;
   8 import org.slf4j.LoggerFactory;
   9 
  10 @ComponentScan //scans for @Component beans 
  11 @EnableAutoConfiguration
  12 @EnableEurekaClient
  13 public class Application {
  14     private static Logger logger;
  15 
  16     public static void main(String[] args) {
  17         logger = LoggerFactory.getLogger(Application.class);
  18         logger.info("Starting application");
  19         SpringApplication.run(Application.class, args);
  20     }
  21 }

src/main/java/chucknorris/bitarus/allowed/org/ChuckNorrisController.java

   1 package chucknorris.bitarus.allowed.org;
   2 
   3 import org.springframework.stereotype.Controller;
   4 import org.springframework.web.bind.annotation.RequestMapping;
   5 import org.slf4j.Logger;
   6 import org.slf4j.LoggerFactory;
   7 import org.springframework.web.bind.annotation.ResponseBody;
   8 import java.io.BufferedReader;
   9 import java.io.InputStreamReader;
  10 import java.net.HttpURLConnection;
  11 import java.net.URL;
  12 import org.springframework.beans.factory.annotation.Value;
  13 import org.springframework.core.env.Environment;
  14 
  15 import com.google.gson.Gson;
  16 import java.util.stream.Collectors;
  17 import java.util.List;
  18 import java.util.ArrayList;
  19 
  20 @Controller
  21 public class ChuckNorrisController {
  22     private final Logger logger = LoggerFactory.getLogger(ChuckNorrisController.class);
  23 
  24     @Value("${server.port}")
  25     private String serverPort;
  26 
  27     private Environment env;
  28 
  29     public ChuckNorrisController(Environment env) {
  30         logger.info("ChuckNorrisController created");
  31         this.env = env;
  32     }
  33 
  34     @RequestMapping("/chucknorris")
  35     @ResponseBody
  36     // http://localhost:8080/chucknorris
  37     public JokeResponse chucknorris() {
  38         String ret = "";
  39         Gson gson = new Gson();
  40 
  41         try {
  42             URL url = new URL("https://api.chucknorris.io/jokes/random");
  43             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  44             connection.connect();
  45             logger.info(Integer.toString(connection.getResponseCode()));
  46 
  47             try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"))) {
  48                 StringBuilder response = new StringBuilder();
  49                 String responseLine = null;
  50                 while ((responseLine = br.readLine()) != null) {
  51                     response.append(responseLine.trim());
  52                 }
  53 
  54                 Joke joke = gson.fromJson(response.toString(), Joke.class);
  55 
  56                 List<Joke> jokesList = new ArrayList<Joke>();
  57                 jokesList.add(joke);
  58                 List<Joke> jokesList2 = jokesList.stream().map(item -> {
  59                     item.setValue(item.getValue().toUpperCase());
  60                     return item;
  61                 }).collect(Collectors.toList());
  62                 joke = jokesList2.get(0);
  63                 ret = joke.getValue();
  64             }
  65 
  66         } catch (Exception ex) {
  67             logger.error("error", ex);
  68         }
  69 
  70         JokeResponse jr = new JokeResponse();
  71         jr.setResponse(ret);
  72         jr.setServerPort(serverPort);
  73         return jr;
  74     }
  75 }

src/main/java/chucknorris/bitarus/allowed/org/Joke.java

   1 package chucknorris.bitarus.allowed.org;
   2 import com.google.gson.annotations.SerializedName;
   3 
   4 public class Joke {
   5 
   6     @SerializedName("categories")
   7     private String[] categories;
   8     @SerializedName("created_at")
   9     private String createdAt;
  10     @SerializedName("icon_url")
  11     private String iconUrl;
  12     @SerializedName("id")
  13     private String id;
  14     @SerializedName("updated_at")
  15     private String updatedAt;
  16     @SerializedName("url")
  17     private String url;
  18     @SerializedName("value")
  19     private String value;
  20 
  21     public String[] getCategories() {
  22         return this.categories;
  23     }
  24 
  25     public String getCreatedAt() {
  26         return this.createdAt;
  27     }
  28 
  29     public String getIconUrl() {
  30         return this.iconUrl;
  31     }
  32 
  33     public String getId() {
  34         return this.id;
  35     }
  36 
  37     public String getUpdatedAt() {
  38         return this.updatedAt;
  39     }
  40 
  41     public String getUrl() {
  42         return this.url;
  43     }
  44 
  45     public String getValue() {
  46         return this.value;
  47     }
  48 
  49     public void setCategories(String[] categories) {
  50         this.categories = categories;
  51     }
  52 
  53     public void setCreatedAt(String createdAt) {
  54         this.createdAt = createdAt;
  55     }
  56 
  57     public void setIconUrl(String iconUrl) {
  58         this.iconUrl = iconUrl;
  59     }
  60 
  61     public void setId(String id) {
  62         this.id = id;
  63     }
  64 
  65     public void setUpdatedAt(String updatedAt) {
  66         this.updatedAt = updatedAt;
  67     }
  68 
  69     public void setUrl(String url) {
  70         this.url = url;
  71     }
  72 
  73     public void setValue(String value) {
  74         this.value = value;
  75     }
  76 }

src/main/java/chucknorris/bitarus/allowed/org/JokeResponse.java

   1 package chucknorris.bitarus.allowed.org;
   2 
   3 import com.google.gson.annotations.SerializedName;
   4 
   5 public class JokeResponse {
   6 
   7     @SerializedName("response")
   8     private String response;
   9 
  10     @SerializedName("serverPort")
  11     private String serverPort;
  12 
  13     public String getResponse() {
  14         return this.response;
  15     }
  16 
  17     public void setResponse(String response) {
  18         this.response = response;
  19     }
  20 
  21     public String getServerPort() {
  22         return this.serverPort;
  23     }
  24 
  25     public void setServerPort(String serverPort) {
  26         this.serverPort = serverPort;
  27     }
  28 }

src/main/resources/application.properties

server.port=8080
spring.application.name=chuck-norris
management.endpoints.enabled-by-default=false
management.endpoint.health.enabled=true
management.endpoint.info.enabled=true
management.endpoints.web.exposure.include=info, health

eureka-server

Acts as a service discovery (service registry and locator). Listens to port 8761. Each microservice when it's launched registers itself in the eureka server.

pom.xml

   1 <?xml version="1.0" encoding="UTF-8"?>
   2 <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">
   3     <modelVersion>4.0.0</modelVersion>
   4     <groupId>bitarus.mooo.com</groupId>
   5     <artifactId>eurekaserver</artifactId>
   6     <version>0.1.0</version>
   7     <parent>
   8         <groupId>org.springframework.boot</groupId>
   9         <artifactId>spring-boot-starter-parent</artifactId>
  10         <version>2.6.7</version>
  11     </parent>
  12     <dependencies>
  13         <dependency>
  14             <groupId>org.springframework.cloud</groupId>
  15             <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  16             <version>3.1.2</version>
  17         </dependency>
  18     </dependencies>
  19     <properties>
  20         <start-class>eurekaserver.bitarus.mooo.com.Application</start-class>
  21     </properties>
  22     <build>
  23         <plugins>
  24             <plugin>
  25                 <groupId>org.springframework.boot</groupId>
  26                 <artifactId>spring-boot-maven-plugin</artifactId>
  27             </plugin>
  28         </plugins>
  29     </build>
  30     <repositories>
  31         <repository>
  32             <id>spring-milestone</id>
  33             <url>http://repo.spring.io/libs-release</url>
  34         </repository>
  35     </repositories>
  36     <pluginRepositories>
  37         <pluginRepository>
  38             <id>spring-milestone</id>
  39             <url>http://repo.spring.io/libs-release</url>
  40         </pluginRepository>
  41     </pluginRepositories>
  42 </project>

src/main/java/eurekaserver/bitarus/mooo/com/Application.java

   1 package eurekaserver.bitarus.mooo.com;
   2 
   3 import org.springframework.boot.autoconfigure.SpringBootApplication;
   4 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
   5 import org.springframework.boot.SpringApplication;
   6 import org.slf4j.Logger;
   7 import org.slf4j.LoggerFactory;
   8 
   9 @SpringBootApplication
  10 @EnableEurekaServer
  11 public class Application {
  12     private static Logger logger;
  13 
  14     public static void main(String[] args) {
  15         logger = LoggerFactory.getLogger(Application.class);
  16         logger.info("Starting application eureka server");
  17         SpringApplication.run(Application.class, args);
  18     }
  19 }

src/main/resources/application.properties

server.port=8761
spring.application.name=eureka-server
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false

springcloud-gw-server

Acts as a load balancer and API gateway. Routes requests to the micro services registered in the eureka server. Listens to port 8111 . Example URL http://localhost:8111/chucknorris/ .

pom.xml

   1 <?xml version="1.0" encoding="UTF-8"?>
   2 <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">
   3     <modelVersion>4.0.0</modelVersion>
   4     <groupId>bitarus.mooo.com</groupId>
   5     <artifactId>spring-cloud-gw-server</artifactId>
   6     <version>0.1.0</version>
   7     <parent>
   8         <groupId>org.springframework.boot</groupId>
   9         <artifactId>spring-boot-starter-parent</artifactId>
  10         <version>2.6.7</version>
  11     </parent>
  12     <dependencies>
  13         <dependency>
  14             <groupId>org.springframework.boot</groupId>
  15             <artifactId>spring-boot-actuator</artifactId>
  16         </dependency>
  17         <dependency>
  18             <groupId>org.springframework.boot</groupId>
  19             <artifactId>spring-boot-starter-webflux</artifactId>
  20         </dependency>
  21         <dependency>
  22             <groupId>org.springframework.cloud</groupId>
  23             <artifactId>spring-cloud-starter-gateway</artifactId>
  24             <version>3.1.2</version>
  25         </dependency>
  26         <dependency>
  27             <groupId>org.springframework.cloud</groupId>
  28             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  29             <version>3.1.2</version>
  30         </dependency>        
  31     </dependencies>
  32     <properties>
  33         <start-class>springcloudgwserver.bitarus.mooo.com.Application</start-class>
  34     </properties>
  35     <build>
  36         <plugins>
  37             <plugin>
  38                 <groupId>org.springframework.boot</groupId>
  39                 <artifactId>spring-boot-maven-plugin</artifactId>
  40             </plugin>
  41         </plugins>
  42     </build>
  43     <repositories>
  44         <repository>
  45             <id>spring-milestone</id>
  46             <url>http://repo.spring.io/libs-release</url>
  47         </repository>
  48     </repositories>
  49     <pluginRepositories>
  50         <pluginRepository>
  51             <id>spring-milestone</id>
  52             <url>http://repo.spring.io/libs-release</url>
  53         </pluginRepository>
  54     </pluginRepositories>
  55 </project>

src/main/java/springcloudgwserver/bitarus/mooo/com/Application.java

   1 package springcloudgwserver.bitarus.mooo.com;
   2 
   3 import org.springframework.boot.autoconfigure.SpringBootApplication;
   4 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
   5 import org.springframework.boot.SpringApplication;
   6 import org.slf4j.Logger;
   7 import org.slf4j.LoggerFactory;
   8 
   9 @SpringBootApplication
  10 @EnableEurekaClient
  11 public class Application {
  12     private static Logger logger;
  13 
  14     public static void main(String[] args) {
  15         logger = LoggerFactory.getLogger(Application.class);
  16         logger.info("Starting application spring cloud gw server");
  17         SpringApplication.run(Application.class, args);
  18     }
  19 }

src/main/resources/application.yaml

When a request made to http://localhost:8111/chucknorris/ is caught it is routed to one of the available micro services with the application name CHUCK-NORRIS .

   1 server:
   2   port: 8111
   3 spring:
   4   application:
   5     name: spring-cloud-gateway
   6   cloud:    
   7     gateway:
   8       routes:
   9       - id: chuckNorrisId
  10         uri: lb://CHUCK-NORRIS
  11         predicates:
  12         - Path=/chucknorris/**    
  13 eureka: 
  14   client:
  15     serviceUrl:
  16       defaultZone: http://localhost:8761/eureka
  17     registry-fetch-interval-seconds: 20
  18 management:
  19   endpoints:
  20     web:
  21       exposure:
  22         include: "*"
  23 # http://localhost:8111/chucknorris/

micro service identify language using Lucene (based on the chuck norris one)

MicroServices (last edited 2023-05-29 10:14:59 by 127)