Spring Boot with Consul

Author: Shazin Sadakath


This is the part 3 of Spring Boot with Consul series I am writing and if you missed part 1, part 2 I highly recommend you follow those. In this session I am planning to explain how to do the following;

Step 1 - Making Consul visible in a Network

Thus far I have run in a local setup and have connected services from within those local setup only. But in this tutorial I am planning to achieve the below setup;

In this setup I have two nodes. Node A is a typical computer where Consul and Microservice Service consumer will be running. Node B is a raspberry pi single board computer where the actual Microservice will be running and will be registering itself to the Consul in Node A. Finally the Consumer in Node A will be using the Microservice in Node B via Consul.

In order to enable this setup we first need to expose the Consul to be visible within a network by providing the Node A IP address to Consul runtime arguments advertise and bind. Also the client argument which makes the HTTP Client also expose itself in the IP address provided. Let's assume Node A is running on IP Address 192.168.1.3 thus Consul needs to started with following runtime arguments. (There are other ways to do this too)

consul agent -advertise 192.168.1.3 -bind 192.168.1.3 -client 192.168.1.3 -dev -enable-script-checks -config-dir=./consul.d

Step 2 - Run the Microservice in Node B (raspberry pi) and Register to Consul in Node A (computer)

The Microservice bootstrap.yml needs to be modified as following to connect to Consul in Node A

spring:
  application:
    name: web
  cloud:
    consul:
      host: 192.168.1.3
      port: 8500
      config:
        watch:
          enabled: true
      discovery:
        preferIpAddress: true

Now we can boot up the Node B and move the Microservice jar there and invoke the following command to start that. 

$ java -jar consul-demo-0.0.1-SNAPSHOT.jar

You can see the following log in the console which registers the "web" Microservice in Consul running in Node A

2020-08-02 06:16:16.189  INFO 979 --- [           main] o.s.c.c.s.ConsulServiceRegistry          : Registering service with consul: NewService{id='web', name='web', tags=[secure=false], address='192.168.1.5', meta={}, port=8080, enableTagOverride=null, check=Check{script='null', dockerContainerID='null', shell='null', interval='10s', ttl='null', http='http://192.168.1.5:8080/actuator/health', method='null', header={}, tcp='null', timeout='null', deregisterCriticalServiceAfter='null', tlsSkipVerify=null, status='null', grpc='null', grpcUseTLS=null}, checks=null}

Now our service is discoverable in Consul and can be viewed in the Consul UI

Have a look at the IP near globe icon which shows the IP and Port in which the "web" Microservice is running.

Step 3 - Discovering and Consuming Microservice via Consul

Finally we can consume the "web" Microservice using a consumer we have written using Spring Boot which is similar to below;

@SpringBootApplication
public class ConsulClientDemoApplication {

    public static void main(String... args) {
        new SpringApplicationBuilder(ConsulClientDemoApplication.class).web(WebApplicationType.NONE).run(args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    public CommandLineRunner commandLineRunner(RestTemplate restTemplate) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        return args -> {
            for (int i=0;i<10;i++) {
                executorService.submit(() -> {
                    String webServiceResponse = restTemplate.getForObject("http://web/", String.class);
                    System.out.println("Web Response for Request : " + webServiceResponse);
                });
            }
        };
    }
}

Take special note of the RestTemplate bean and its special annotation @LoadBalanced. Also during the invocation of the restTemplate.getForObject method we have used the Consul service name "web" not a DNS or IP address. This guarantees that we consume the Consul registered service.

The consumer has the following bootstrap.yml configuration

spring:
  application:
    name: webclient
  cloud:
    consul:
      host: 192.168.1.3
      port: 8500
      discovery:
        preferIpAddress: true

Finally when we run the Consumer we would see the following output. 

2020-08-02 12:05:23.111  INFO 2480 --- [pool-1-thread-7] c.netflix.loadbalancer.BaseLoadBalancer  : Client: web instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=web,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2020-08-02 12:05:23.124  INFO 2480 --- [pool-1-thread-7] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2020-08-02 12:05:23.185  INFO 2480 --- [pool-1-thread-7] c.netflix.config.ChainedDynamicProperty  : Flipping property: web.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-02 12:05:23.188  INFO 2480 --- [pool-1-thread-7] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client web initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=web,current list of Servers=[192.168.1.5:8080],Load balancer stats=Zone stats: {unknown=[Zone:unknown; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:192.168.1.5:8080; Zone:UNKNOWN; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 05:30:00 IST 1970; First connection made: Thu Jan 01 05:30:00 IST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:ConsulServerList{serviceId='web', tag=null}
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
Web Response for Request : Hello , 10 from raspberrypi
2020-08-02 12:05:24.158  INFO 2480 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: web.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
Web Response for Request : Hello , 10 from raspberrypi

That's all for this tutorial. The source code is available at https://github.com/shazin/spring-boot-consul. Let's learn more in coming weeks. Register with us for more informative posts like this one.



Tags: SpringBoot Consul Microservice ServiceDiscovery ServiceRegistry
Views: 539
Register for more exciting articles

Comments

Please login or register to post a comment.


There are currently no comments.