Api Gateway Part 3: Zuul & Consul

Nepal Brothers
5 min readMar 3, 2019

--

This blog is a part of building scalable Spring Boot microservices based project. It comprises of creating connecting microservices using Zuul, service discovery using Consul, security using Spring Security, distributed session using Spring Session and products such as MongoDB, Redis. Here is the chronological sequence of how I wrote article. https://medium.com/@nepalBrothers/web-development-scalable-web-app-using-spring-boot-and-spring-cloud-1f9960e1d61a

Over the series, we have developed the following architecture with the following:

  1. an API-Gateway using Zuul
  2. stateful microservice Account, whoAmI and stateless microservice Product
  3. Able to handle Authentication by using Account service
  4. Distributed Session using Redis, and database as MongoDB

Show me the code

The code also contains how to run

What can we do more?

Currently, our microservice is bind with Ports. In the real world scenario, there will be multiple instances of microservice, and serving the traffic using the port will not be maintainable.

The solution to that is to call the services using the serviceId. This way, we will call the serviceId, and based on what Id is returned, we will call that IP automatically. A serviceId can represent multiple services registered to it under the same serviceId.

For instance, our Api-Gateway will call by the serviceId, and when we make a call to that serviceId, it will in turn make a call to any of those load balanced instances. This way, we can scale as much as we want.

We do so by using Consul for this case. There are alternatives as well, such as Netflix’s Eureka. However, Consul is more powerful than Eureka. There is more to Consul and we can read it in official site, but I will quickly show how I was able to integrate Consul to the designed microservices.

Make Api-Gateway use Consul

For this, we will need to add Consul dependencies in our project. Best way to pull up dependencies is Spring Initializer. We can add these dependencies to our old pom.xml file

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>

Also, Annotating our Spring Boot application with EnableDiscoveryClient will make our API-Gateway discoverable by Consul.

@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
class ApiGatewayApplication

Run Consul

Once Consul is installed, we can run it with the following command:

consul agent -dev -node machine

This basically tells the consul agent to start as dev and assign the name of the node to machine

Run our API Gateway

We can see this in the logs once we Run our API-Gateway.

Also, Consul provides us its UI, which comes handy to manage and see the consul. http://localhost:8500/ui/dc1/services

We can see a red cross in our apiGateway, and it is because Consul does Health Check to see if this service is up and running. Consul will only send the traffic to healthy services only.

Currently, Consul is not able to check the health. So, one way to resolve is to add spring actuator in the classpath, which will then provide endpoints for healthcheck.

Add this in pom.xml dependency

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Modify Zuul properties so that it knows actuator healthchecks are not available for proxying to downstream services.

zuul:
ignored-patterns: /actuator/**

Lets restart and see if it resolves the issue

Awesome! We have now set our API-Gateway to use Consul.

Lets make our microservices Discoverable and have Zuul use Consul Services

Making our existing microservices discoverable with Consul is easy. We only need to add dependency.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--for health check -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

And we just need to make the services discoverable by adding annotation:

@EnableDiscoveryClient

Also, if the old projects don’t have Spring Cloud in the pom.xml, we need to add them as well.

Just like our Product microservice did not have it, we had to modify pom.xml for that. We can add this under <project>

<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>

and

<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>

inside <properties> tag.

We need to do this for those services whom we want to be discoverable. This means, Account, whoAmI, Product service, as well as API-Gateway.

Lets tell Zuul to consider serviceId than uri

We just need to modify a little bit in the bootstrap.yml file for it.

zuul:
ignored-patterns: /actuator/**
routes:
product:
path: /product/**
serviceId: product
# url: http://localhost:8080
stripPrefix: true


whoAmI:
path: /whoAmI/**
serviceId: whoAmI
# url: http://localhost:8092
stripPrefix: true
sensitiveHeaders:

account:
path: /**
serviceId: account
# url: http://localhost:8091
stripPrefix: false
sensitiveHeaders:

Thats it.

Now, lets run the services. They themselves register to the consul and make them available.

Lets check

We can check them by going to http://localhost:8500/ui/

Great. We can now refer to the serviceId than the IP, which is awesome.

Lets check product endpoint:

As we can see it is working.

--

--

Responses (1)