Microservices / Networking

Implementing Service Discovery of Microservices with Consul

26 Jun 2019 10:09am, by

Consul from HashiCorp is one of the early implementations of service mesh technology. It comes with a full-featured control plane with service discovery, configuration, and segmentation functionality. The best thing about Consul is the support for a variety of environments including traditional applications, VMs, containers, and orchestration engines such as Nomad and Kubernetes.

At a high level, Consul provides the below functionality:

  • Distributed Architecture: Consul supports multiple data centers and for delivering a scalable, highly available, abstract, and resilient service mesh infrastructure. A Consul deployment may span multiple zones or even regions in a public cloud environment.
  • Service Discovery: Distributed applications can use Consul to dynamically discover service endpoints. Once a service is registered with Consul, it can be discovered using typical DNS or custom API.
  • Health Checking: Consul can track and report the health of registered services. Each microservice can provide an endpoint that Consul probes to check the health. This is useful in implementing patterns such as circuit-breaking.
  • Key/Value Store: Consul is one of the popular distributed, in-memory KV store. Applications and infrastructure can utilize to store hierarchical data that’s accessible to any participating service. A simple HTTP API exposes the read/write functionality to deal with the data.
  • Secure Communication: Like most of the service mesh implementations, Consul enables implicit communication security for services through mTLS. The traffic between the proxies/sidecars is automatically encrypted without the need to code or configure.

This tutorial explores the concepts of Consul through a simple scenario based on three microservices.

We have three microservices — order, invoice, and tax — that are a part of an online retail application. Order invokes the invoice service which in turn calls the tax service.

These microservices are written in Flask with a very simple functionality — they return the service name and the version.

The order, invoice, and tax microservices are listening on ports 5000,5001, and 5002 respectively.

Let’s launch the services and invoke them.

The URI of the upstream service is passed as an environment variable. Invoking order service listening on 5000 will print the below output:

We will now register these microservices with Consul for dynamic service discovery.

Installing and Running Consul

Download an appropriate flavor of the Consul binary from HashiCorp’s official website, and move it to a directory which is added to your $PATH environment variable.

Launch Consul with the below command line switches.

The -dev switch instructs Consul to run in a development environment. The -ui parameters launches makes the dashboard available. The -datacenter and -node provide identifiers for the datacenter
and the host.

Visiting http://localhost:8500/ui will show the Consul dashboard.

Since we are have not registered the services, the dashboard looks empty. Let’s populate it with our microservices.

Registering Microservices with Consul

Before we can dynamically discover the services, we need to register them with Consul. This is done by creating a Consul service definition file for each service with the name and the port.

The below JSON document saved in a file named order.json represents the order service definition.

Create the definitions for the other services and move the JSON files to a directory called consul.d

With the service definition files in place, we will relaunch Consul pointing it to consul.d directory to load the definitions. The config-dir switch tells Consul to include all the configuration files in the directory.

Hit CTRL+C to terminate the Consul agent and relaunch it with the below command.

The Consul web UI now shows the registered services.

Discovering the Services with DNS and HTTP API

Consul has its own DNS server listening on port 8600 that can respond to standard queries. Each registered service gets its own DNS entry which resolves to the service endpoint.

Each service assumes a FQDN in the format of service_name.service.consul. Consul will resolve the name to the exact service running in a specific data center and node.

The below command shows how Consul resolves the order microservice endpoint.

The SRV record shows the port (5000) and the location (host1.node.zone1.consul) where the service endpoint is hosted. Feel free to explore the DNS entries for invoice and tax services.

Applications can query the HTTP API for discovering the service.

We can integrate Consul DNS with the host DNS to resolve service FQDN. On macOS Mojave, updating /etc/resolver/consul with the below entry makes this possible.

You can now resolve the service names with FQDN.

In the next part of this tutorial, to be posted Friday, we will take a look at Consul Connect, the service mesh component of Consul. Stay tuned.

Janakiram MSV’s Webinar series, “Machine Intelligence and Modern Infrastructure (MI2)” offers informative and insightful sessions covering cutting-edge technologies. Sign up for the upcoming MI2 webinar at http://mi2.live.

Feature Image by DarkWorkX from Pixabay.